پیوند و اجرای اسمبلی

simona

New Member
سلام
کارتون حرف نداره . واقعا" خسته نباشید.
اگه ممکنه در مورد جمع وضرب هم توضیح بدید.البته قبلا"هم بهش اشاره کرده بودید ولی من تو محاسبه این عبارت مشکل دارم.
کد:
)(a^2+b^2)/(a^2-b^2)
 

saalek110

Well-Known Member
سلام دوست من. ممنون از لطفت.
اما ضرب و جمع:
هر رجيستر 16 بيتي توانايي نگه داشتن عددي به بزرگي ffff يعني 65535(مبناي 10 ) را دارد.

دستور جمع add است و دستور ضرب mul .
در شكل زير عمل جمع انجام شده. و ده بر يك(يا بهتر بگيم 16 بر يك ) داشته.

2e4ityq.gif


عدد 9 بعلاوه 7 ميشه 16 ، پس 16 بر يك داشته ايم. و 16 بر يك آخري رفته بيرون و داخل فلاگ carray قرار گرفته.
اگر بخواهيد از ده بر يك استفاده بشه به جاي add از adc حالا استفاده كنيد:

34q8okp.gif


در شكل بالا 2 بعلاوه 3 شده 6 چون فلاگ نقل پر بوده. و مي بينيم كه بعد adc خالي شده. چون جمع شده با عدد ها.
= == = == == =
اين از جمع :
فكر كنم توضيحات كافي باشه. ديگه نوشتن كدش سليقه اي است كه اگر خواستيد بياوريد با هم هم فكري كنيم.

حالا ضرب:

4h0qptg.gif


ضرب e
(14 در مبناي 10 )
ضرب در 3
ميشه
42
كه ميشه
32 بعلاوه 10
كه ده اش ميشه a
كه در رقم اول ax مشاهده ميشه
و 32 اش ميشه
دو تا 16 تا
كه با a رقم بعدي ax كه جمع بشه ميشه c
(a+2=c )
. پس همه مي شوند c تا آخر.
و يك 2 هم بيرون ميافتد كه رفته داخل dx .
نتيجه گيري:
ارقام بزرگ به dx مي روند و ارقام كوچك در ax .
براي به توان 2 رساندن يك عدد هم من پيشنهاد مي كنم اين عدد را با قرار دادن در ax و bx و با دستور بالا در خودش ضرب كنيد. شايد هم راه بهتري باشد ولي من اين به ذهنم مي رسد.
=========
در مورد تقسيم هم دقيقا مثل ضرب است. كه حاصل تقسيم در ax و باقي مانده در dx قرار مي گيرد.
دستور:
div bx
 
آخرین ویرایش:

saalek110

Well-Known Member
اما راجع به اون اموليتور دو پست قبل : پيشنهاد مي كنم دانلود كنيد. به خاطر نمونه برنامه هاي ساده آن و آموزش دستورات اسمبلي مي گويم. هر چند كه شبيه سازش هم خيلي خوبه و اديتورش هم خوبه.
==============
==============
يك سر هم به اين سايت بزنيد شايد بشه رفرنس شما:
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html
 
آخرین ویرایش:

saalek110

Well-Known Member
اما تفريق:
در برنامه اول شكل زير مي بينيد كه هيچ فلاگي تغيير نكرده.
در شكل زير در برنامه دومي 8 از 7 كم شده. مي توانيم ffff را منفي يك در نظر بگيريم. 4 فلاگ تغيير كرده.
كلا در اسمبلي دو حالت اعداد علامت دار و بي علامت را در نظر ميگيرند. در حالت اعداد علامت دار ، آخرين بيت را علامت منفي در نظر مي گيرند. در حالت اعداد علامت دار ديگه تا 65536 در رجيستر جا نميشه و نيمي از اين مقدار را داريم. همان 32 هزار معروف . كه در زبان سي به عنوان integer مي شناسيم.
ديگه اين كه بخواهيم علامت دار كار كنيم يا بي علامت دو بحث مختلف ميشه.


315mye1.gif


اما در برنامه دوست عزيز سيمون، به نظر من تعريف كردن زيربرنامه ((به توان 2 رساندن)) خيلي به خلوت شدن محيط كمك مي كند.
و يك راه براي بهتر كردن فهم برنامه استفاده از متغيرهايي با dw (كلمه) است تا نتايج را كه در ax و dx درمي آيد را در آنها بريزيم. ميشه دو word با نام sum1 و sum2 داشت براي dx و ax . و زيربرنامه توان رساندن خروجي خود را در اينها برگرداند. و ميشه دو متغير از اين نوع هم مثلا براي نتيجه كل در نظر گرفت. و شايد خوب باشه يك متغير هم براي علامت در نظر گرفت يا اينكه اين متغير علامت چيز خوبي نباشه و با روش علامت دار بودن رجيسترها كار راحت تر پيش برود.
كلا راجع به علامت در اين پست خوب كار نشده و بعدا بايد اين بحث خوب مورد تجزيه تحليل قرار گيرد. دوستان هم مطلبي اگر دارند اگر ارائه كنند خيلي خوبه.
 
آخرین ویرایش:

saalek110

Well-Known Member
نقل از Inprise :
http://barnamenevis.org/forum/showthread.php?t=21044

اديتور كروم:
کد:
Integrated Development Environment for Asm/C/Pascal and more.

Main features are:

- Adaptive to various languages.
- Visual skins for compilers/assemblers.
- Integrated PILL script engine (with scriptable wizards and scripts per language). 
- AddIn system providing more than 600 functions.
- Versatile user menus editor.
- Import/Export filters with chaining ability.
- Full integration with MS SDK / DDK / DXSDK.
- Customizable help system per language.
- Extended edition capabilities.
- APIs code completion.
- Projects manager.
- Free.

This tool is still under development and the integrated debugger and dialogs editor aren't finished yet.
It may be or may not be completed depending on the time / will / feedback i'll have / receive.	
.

chrome_capt1.gif




chrome_capt2.gif


سالك:
حجم : دو مگا.
رنگي بودن و احضار اتوماتيك كامپايلر كمك به رفاه برنامه نويس مي كند.

لينك سايت:
http://perso.orange.fr/franck.charlet/Chrome.html
 
آخرین ویرایش:

saalek110

Well-Known Member
کد:
Hi,
These commands change the ZF for you.

POPF = Pop flags
ADD = Add
ADC = Add with Carry
SUB = Subtract
SBB = Subtract with borrow
INC = Increment
DEC = Decrement
SAL = Shift arithmetic left (SHL)
SAR = Shift arithmetic right
NEG = Negate (two-complement)
AND = Logical and
OR  = Logical or
XOR = Logical exclusive or
SHL = Shift logical left (SAL)
SHR = Shift logical right

Bye for now.
مطلب بالا نقل از دوستي عزيز.
-------------------
سالك:
من خودم يك كتاب چاپ دارم كه زير هر دستور نوشته كه كدام فلاگ را تغيير مي دهد. ولي اين طوري دسته بندي نكرده.
دستورات بالا را هم تست نكردم كه ببينم فلاگ تغيير مي كنه يا نه.

ولي در مورد پرشهاي شرطي كار ساده تره . چون اونها 10 تا بيست تا بيشتر نيستند و معمولا به يكي دو تا يا سه تا فلاگ نگاه مي كنند.

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

saalek110

Well-Known Member
با سلام.
يك سايتي من پيدا كردم كه مبتدي شروع كرده. و يك خوبي هم كه داره اينه كه سينتكس tasm را با masm مقايسه كرده.

در مورد كار با tasm بعدش انگار با tlink بايد لينك كرد كه من در طول اين تاپيك با link كار كردم كه انگار مال masm بوده. ولي هيچ وقت مشكلي نداشتم.

در مورد masm هم بعدش با link كار مي كنيم.

= == = = = = = = ==
در 10 تا بيست فصل بحث كرده كه در دو صفحه زير لينك فصل هايش هست:

http://www.developer.be/index.cfm/fuseaction/tutorialList/GroupID/17/GroupName/Assembler.htm

http://www.developer.be/index.cfm/f.../GroupID/17/GroupName/Assembler/pageNum/2.htm
 

saalek110

Well-Known Member
اين هم خوش آمدش:
= = = = = = = =
Hi! Welcome to low-level world! This time I would like to explain the basic concepts of low level. This part is merely directed toward Intel PC. I'd like to add more for other computers like Mac and Amiga, but I think time wouldn't allow me to do this in near future. :)

هاي . به دنياي low-level خوش آمديد. در اينجا من مي خواهم تصور كلي ئي راجع به پايه دنياي low-level ايجاد كنم. و اين جا براي intel pc بحث مي كنيم. من دوست داشتم تا راجع به مكينتاش و آميگا هم بحث كنم ولي فكر نمي كنم وقت بكنم.
سالك: در تاپيكهاي فارسي خواندم كه برنامه اي كه براي اينتل بهينه شده بر مكينتاش بهينه نيست. بيشتر اطلاعات ندارم و جمله بالا را هم نمي توانم نقد كنم.

Registers

What is registers exactly? You can consider it as variables inside the CPU chip. Yeah! That depicts registers so close. There are several registers exist in PC:

AX, BX, CX, DX, CS, DS, ES, SS, SP, BP, SI, DI, Flags, and IP​

رجيسترها:
رجيستر واقعا چيست؟ شما مي توانيد آن را متغيري داخل cpu در نظر بگيريد. اوه، اين تعريف خيلي محدود مي كنه ما را. (س: ترجمه را ببين!) . رجيسترهاي متعددي در pc وجود دارد: ليست بالا.

They are all 16-bits. You can treat it as if they are word (or unsigned integer) variables. However, each registers has its own use.​

آنها همگي 16 بيتي هستند. شما مي توانيد آنها را word يا اينتيجر بي علامت در نظر بگيريد. ولي هر رجيستر استفاده خودش را دارد.

AX, BX, CX, and DX are general purpose registers. They can be assigned to any value you want. Of course you need to adjust it into your need.​

رجيسترهاي ax bx cx dx رجيسترهايي براي مصارف عمومي اند. آنها مي توانند هر مقداري را كه شما مي خواهيد به خود بگيرند. پس شما مي توانيد آنها را تنظيم كنيد براي نياز خود.

AX is usually called accumulator register, or just accumulator. Most of arithmatical operations are done with AX. Sometimes other general purpose registers can also be involved in arithmatical operation, such as DX.​

رجيستر ax معمولا ((رجيستر جمع كننده)) ناميده مي شود. يا به طور مخفف جمع كننده. بيشتر عمليات رياضي با ax انجام مي شود. بعضي اوقات هم رجيسترهاي همه منظوره ديگر براي اين كار استفاده مي شوند مثل dx .


The register BX is usually called base register. The common use is to do array operations. BX is usually worked with other registers, most notably SP to point to stacks.​

رجيستر bx به نام base register ناميده مي شود. كاربرد عمومي آن براي محاسبات آرايه اي است.
اين رجيستر معمولا با بقيه رجيسترها با هم بكار مي رود ، كار قابل ملاحظه اش با sp براي اشاره به پشته است.

The register CX is commonly called counter register. This register is used for counter purposes. That's why our PC can do looping.​

رجيستر cx اكثرا به نام counter register به كار مي رود. اين رجيستر براي مقاصد شمارش به كار مي رود. و اين علت اين است كه چطور pc ما مي تواند حلقه ايجاد كند.

DX register is the data register. It is usually for reserving data value.​

رجيستر dx كه data register است معمولا براي رزرو مقادير ديتا استفاد مي شود.

= = = =
The registers CS, DS, ES, and SS are called segment registers. You may not fiddle with these registers. You can only use them in the correct ways only.​

رجيسترهاي cs ds es ss به نام رجيسترهاي سگمنت ناميده مي شوند. شما نمي توانيد كارهاي نسنجيده با اينها بكنيد. شما فقط مي توانيد آنها را، فقط، با راه درست بكارگيري آنها ، بكار بريد.

CS is called code segment register. It points to the segment of the running program. We may NOT modify CS directly. Oh yes, what is "segment" anyway? It's discussed later. :)

رجيستر cs به نام code segment register ناميده مي شود. آن به سگمنت برنامه در حال اجرا اشاره مي كند. ما نبايد cs را مستقيما دستكاري كنيم. اوه ، بله ، چه هست سگمنت؟ آن بعدا شرح داده خواهد شد.

DS is called data segment register. It points to the segment of the data used by the running program. You can point this to anywhere you want as long as it contains the desired data.​

رجيستر ds به نام data segment ناميده مي شود. آن اشاره مي كند به سگمنت داده. شما مي توانيد با آن به هر جايي كه اطلاعات داريد اشاره كنيد.


ES is called extra segment register. It is usually used with DI and doing pointers things. The couple DS:SI and ES:DI are commonly used to do string operations.​

رجيستر es به نام extra segment register ناميده مي شود . آن اغلب با di استفاده مي شود و كار نشانه روي انجام مي دهد. زوج ds و si و زوج es و di عموما استفاده مي شوند براي كار با رشته ها.

SS is called stack segment register. It points to stack segment.​

رجيستر ss به نام رجيستر استك (پشته) خوانده مي شود. آن به قطعه پشته اشاره مي كند.
 
آخرین ویرایش:

simona

New Member
سلام آقا سالک
از راهنماییتو ن ممنونم.
می تونم در مورد حلقه ها در اسمبلی هم سوال بپرسم تا با هم فکری هم حلش کنیم؟ راستش برای من خیلی گیج کننده ست .
 

saalek110

Well-Known Member
خيلي هم خوشحال مي شوم.
من در حال يادگيري ام و تمرين براي من خيلي مفيده.
.
 

simona

New Member
برنامه ای که شکل زیر رو چاپ کنه.
کد:
* * * * *
* - + + *
* + - + *
* + + -*
* * * * *
دو تا حلقه می خواد که 3 تا شرط داشته باشه.
 

saalek110

Well-Known Member
براي مقدمه اي براي شروع كار بايد بگم كه حلقه در اسمبلي دو نوع است:
يكي با loop كه به cx نگاه مي كند و ديگري با پرشهاي شرطي كه به فلاگ ها نگاه مي كنند.

در مورد loop كه ما مي آييم اول به cx مقدار مي دهيم و بعد دستور loop به تعداد عدد موجود در cx پرش مي كند .

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

الان برنامه شما را نگاه مي كنم و بحث را شروع مي كنيم.
 

simona

New Member
الگوریتم برنامه (به نظر من)
کد:
i=1 to n
j=1 to n
{
if(i==1 || j==1||i==n||j==n)
print *
elseif (i==j )
print -
elseif(i!=j)
print +
شاید اجرای این الگوریتم با اسمبلی سخت باشه .اگه شما راه بهتری سراغ دارید پیشنهاد بدید.
 

saalek110

Well-Known Member
سيمون جان من دقيقا الگوريتمي كه در ذهنم بود منطبق بر الگوريتم شماست.
حلقه هاي تو در توي آن آماده است و در زير مي بينيد . فقط مي ماند شرطهاي داخل حلقه . همان ها كه شما در پست اخير خود گفتيد كه تكميل مي كنم.
اين را هم بگويم كه من قبل اين تاپيك ماهها سي و php كار كردم و مي دانيد كه سبك رايج كدنويسي در اين دو زبان دقيقا از الگوريتم شما تبعيت مي كند. شايد در اسمبلي راههاي بهتري باشد ولي كد من و خودتان را سبك يك سي نويس بدانيد.
== == == == =
نوشته ها و كدهاي زير را من قبل خواندن پست آخر شما آماده كرده بودم كه بدون ويرايش مي زنم:
= = == == = == == = = = = =
من از تمرين بالا اين گونه استنباط مي كنم كه مي خواهد كادري با ستاره بكشد و با بعلاوه پر كند داخل كادر را و قطرش را هم با منها بكشد.
ولي در مورد اين شكل مي شود 5 رشته كاراكتري در ديتا سگمنت تعريف كرد و پشت سر هم آنها را رسم كرد. ولي موضوع بحث ما اين نيست. پس من مي روم سراغ رسم آن شكل بزرگ.

براي اين كار اول من از وقفه اي استفاده مي كنم كه مكان كرزر را تغيير دهد.
اموليتوري كه گفتم حتما دانلود كنيد يك سري آموزش همراهش است كه ليست وقفه ها را هم دارد. من به اين ليست الان مراجعه مي كنم.
به اين وقفه توجه كنيد:
کد:
INT 10h / AH = 02h - set cursor position.

input:
DH = row.
DL = column.
BH = page number (0..7).

حالا من برنامه ساده اي مي نويسم كه از اين وقفه استفاده كنم.
براي اين كار قالبي را كه قبلا استفاده كرده ام و براي ساخت يك فايل exe است را مي آورم. بين دو خطي كه با منها كشيده ام برنامه خود را مي نويسم. دو خط هم براي انتظار گذاشتن برنامه گذاشتم تا زود بسته نشود. اگر ديديد لازم نيست حذف كنيد اين دو خط را. برنامه زير فقط محل كرزر را به نقطه مورد نظر مي برد. يعني به نقطه 5 و 9 .
کد:
.model small
.stack 
.data 
.code 
asli proc
; -----------------------

mov dh,5  ;DH = row. 
mov dl,9  ;DL = column.
mov ah,2  ;service
int 10h   
;--------wait for a key
MOV AH,00H 
INT 16H 
; -----------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli

حالا با يك سرويس در اين نقطه علامت * (ستاره) را رسم مي كنم. كه كد اسكي آن 2a است.
کد:
.model small
.stack 
.data 
.code 
asli proc
; -----------------------

mov dh,5  ;DH = row. 
mov dl,9  ;DL = column.
mov ah,2  ;service
int 10h  
;----
mov dl,2ah
mov ah,2
int 21h 
;--------wait for a key
MOV AH,00H 
INT 16H 
; -----------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli

حالا حلقه ساده اي با loop مي سازم.
کد:
.model small
.stack 
.data 
.code 
asli proc
; -----------------------
mov cx,0ah
mov dh,0  ;DH = row. 
mov dl,0  ;DL = column.

lable1:
inc dl
mov ah,2  ;service
int 10h  
;----
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 

loop lable1
;--------wait for a key
MOV AH,00H 
INT 16H 
; -----------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli

در برنامه بالا از lable1 حلقه شروع مي شود و در loop انتهاي حلقه قرار دارد. قبل شروع حلقه به سطر و ستون يعني dh و dl مقدار اوليه صفر داده ايم. و cx كه برابر 10 است هم بايد قبل حلقه براي تعداد چرخش تنظيم شود. نگاه كنيد كه cx را 0ah گرفته ام نه ah .همين الان بجاش ah گذاشتم كه tasm خطا گرفت. قانون اينه كه اگر عدد مبناي 16 ئي با حرف شروع بشه بايد قبلش يك صفر گذاشت .
نكته بعدي اينه كه مقدار اوليه را داخل حلقه قرار ندهيد چون واضح است كه داخل حلقه مدام اين مقدار در آنها ريخته مي شود و حلقه ما كاري نمي تواند انجام دهد. من داخل حلقه آمده ام dl را در هر چرخش حلقه يكي افزايش داده ام چون مي خواهم اين رسم بشه:
**********
يعني 10 تا ستاره كنار هم داخل سطر اول.

نكته ديگه برنامه اينه كه چون dl جزو مختصات ستاره است نبايد دستكاري بشه پس آنجا كه push و pop كرده ام dx را براي جلوگيري از اين دستكاري است.
نكته ديگر كه inc dl را در انتهاي حلقه گذاشته ام تا اول چاپ انجام بشه و بعد افزايش صورت بگيرد. وگرنه همون اولي هم بعد يكي جلو رفتن چاپ ميشد.
نتيجه اجرا:
همان 10 ستاره به شكل كنار هم (افقي)

= == = = == = = = =
در ادامه مي خواهم 100 تا ستاره رسم كنم كه هر ده تا در يك سطره.
مي خواهم از همان حلقه تو در توي فقط با cx استفاده كنم كه قبلا شرح داده شده.

کد:
.model small
.stack 
.data 
.code 
asli proc
; -----------------------
mov cx,0ah
mov dh,0  ;DH = row. 
mov dl,0  ;DL = column.
; --------- outer loop ---
lable2:

push cx
MOV CX,10
mov dl,0  ;DL = column.
lable1:

mov ah,2  ;service
int 10h  
;----
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 

inc dl  ; increase dl...
loop lable1
pop cx
inc dh  ; increase dh...
loop lable2
;--------wait for a key
MOV AH,00H 
INT 16H 
; -----------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli

براي راحتي شما قالب حلقه تو در تو را هم اينجا مي آورم تا راحت مقايسه كنيد:
کد:
MOV cX,6  
; --------------- outer loop -------------- 
ROW :

; --------- inner loop -------
push cx
MOV CX,10 
COL :

LOOP COL   ; DOWN TO CX=0
pop cx
; ----------------------------


LOOP ROW    ; ELSE JUMP TO ROW 
; -----------------------------------------

نتيجه اجراي برنامه:
چاپ 100 ستاره كه هر ده تا در يك رديف است.

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

saalek110

Well-Known Member
در برنامه پست قبلي به جاي :
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx

اين را قرار مي دهيم:
کد:
cmp dh,dl
jne lable3
push dx
mov dl,2dh
mov ah,2
int 21h
pop dx 
jmp lable4
lable3:
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 
 
lable4:

اين باعث مي شود كه قطر برنامه با علامت منها پر شود و بقيه مكانها با همان ستاره پر شود.

شرح برنامه:
با دستور cmp مي آييم dh و dl را مقايسه مي كنيم.
بعد از شرط jne استفاده مي كنيم كه من معني اش مي كنم jump if not equal .
يعني ((پرش كن وقتي برابر نبود)).
برنامه اين طوريه كه وقتي برابر بود پرش نمي كنه و تكه كد بعدي كه چاپ منهاست اجرا ميشه و منها رسم ميشه. بلافاصله بعد رسم منها با پرش به lable4 من مانع شدم كه هم منها رسم بشه و هم ستاره (كدش 2a است) .
معلومه كه اگر equal نباشند اين jne پرش مي كند به lable3 و نمي گذارد كه منها چاپ بشه.نتيجه اجراي اين كد:

34igzft.gif


بقيه شرطها هم به همين شكل اضافه ميشه. ميشه زيربرنامه هم استفاده كرد.
 

saalek110

Well-Known Member
اين هم برنامه كامل شده:
چيز جديدي ندارد. تكرار شرط هاست.
فقط يك نكته اين كه مواظب باشيد ليبل هاي هم نام نداشته باشيد.
برنامه زير ممكنه قابل بهينه كردن باشد كه من بهينه نكردم.
کد:
.model small
.stack 
.data 
.code 
asli proc
; -----------------------
mov cx,0ah
mov dh,0  ;DH = row. 
mov dl,0  ;DL = column.
; --------- outer loop ---
lable2:

push cx
MOV CX,10
mov dl,0  ;DL = column.
lable1:

mov ah,2  ;service
int 10h  
;-------- cmp's ------
; --- 1 th cmp
cmp dh,0
jne lable5
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 
jmp lable4
lable5:
;----
; --- 2 th cmp
cmp dh,9
jne lable6
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 
jmp lable4
lable6:
;----
; --- 3 th cmp
cmp dl,0
jne lable7
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 
jmp lable4
lable7:
;----
; --- 4 th cmp
cmp dl,9
jne lable8
push dx
mov dl,2ah
mov ah,2
int 21h
pop dx 
jmp lable4
lable8:
;----

; --- ghotr cmp
cmp dh,dl
jne lable3
push dx
mov dl,2dh
mov ah,2
int 21h
pop dx 
jmp lable4
lable3:
; --------- end cmp's ---
push dx
mov dl,2bh
mov ah,2
int 21h
pop dx 
 
lable4: 

inc dl  ; increase dl...
loop lable1
pop cx
inc dh  ; increase dh...
loop lable2
;--------wait for a key
MOV AH,00H 
INT 16H 
; -----------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli


2gt0u4k.gif

.
.
 

saalek110

Well-Known Member
برنامه گرفتن ساعت كامپيوتر:
برنامه زير اين طوري نشان مي دهد:
کد:
1133-3200-11
كه يعني ساعت 11 و 33 دقيقه و 32 ثانيه است. و 11 ساعت هم از نيمه شب گذشته.
با تغيير ساعت كامپيوتر خود ببينيد من درست گفتم يا نه.
در كد قسمتي help همان اموليتوره كه من نقل كردم. اصل برنامه هم اين كده:
mov ah,2
int 1ah
مي توانيد اين دو خط كد را برداريد و باقي اش را خودتان بنويسيد. البته با وقفه هاي ديگر هم فكر كنم ساعت را بشه نمايش داد. خروجي را هم در كدها مي بينيد كه بايد در آن رجيسترها دنبالش بگرديد.

بقيه برنامه جز اين دو خط كد:
با احضار زير برنامه bl_print چاپ رجيستره تا ببينيم ساعت چنده. شايد من جاهايي غلط نوشتم . خودتان اصلاح كنيد. . نمي دانم چرا dl تغيير نمي كنه.شايد هم دليلي نداره كه تغيير كنه. چون ثانيه در dh بود و تمام شد ديگه.اين برنامه براي تنوع بود.
اين تكه هم كه براي چاپ منهاست. براي احتياط رجيستراش را پوش كردم.
push dx
push ax
mov ah,2
mov dl,'-'
int 21h
pop ax
pop dx

کد:
.model small
.stack 
.data 
.code 
asli proc
;---------------------------
;INT 1Ah / AH = 00h - get system time.

;return:

;CX:DX = number of clock ticks since midnight.
;AL = midnight counter, advanced each time midnight passes.

;Notes:
;There are approximately 18.20648 clock ticks per second,
;and 1800B0h per 24 hours. 
;AL is not set by emulator yet! 
;----------------------
mov ah,2
int 1ah

mov bl,ch
call bl_print
mov bl,cl
call bl_print
;------
push dx
push ax
mov ah,2
mov dl,'-'
int 21h
pop ax
pop dx
;------
mov bl,dh
call bl_print
mov bl,dl
call bl_print
;------
push dx
push ax
mov ah,2
mov dl,'-'
int 21h
pop ax
pop dx
;------
mov bl,al
call bl_print

;---------------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
; ============ sub bl_print ===========
bl_print PROC NEAR
push ax
push bx
push cx
push dx
;----------part 1
mov ah,2h
mov dl,bl  

mov cl,04h
shr dl,cl

add dl,30h

cmp dl,3ah
jl lable1

add dl,07h

lable1:
int 21h

; -----------part 2

mov dl,bl
and dl,0fh

add dl,30h

cmp dl,3ah
jl lable2

add dl,07h

lable2:
int 21h
;------------
pop dx
pop cx
pop bx
pop ax

ret ; return to where it was called
bl_print ENDP
;===================================

     end asli
براي تفريح بيشتر من حلقه كردم اول و آخر برنامه را.
البته براي خروج هم چيزي در نظر نگرفتم. اين تكه را انداختم آخر برنامه:
;============
mov dh,0 ;DH = row.
mov dl,0 ;DL = column.
mov ah,2 ;service
int 10h
jmp lablexxx
;===========
كه كرزر را مي آورد اول صفحه. و بعد جامپ مي كند به اول برنامه در lablexxx .
کد:
.model small
.stack 
.data 
.code 
asli proc
;---------------------------
;INT 1Ah / AH = 00h - get system time.

;return:

;CX:DX = number of clock ticks since midnight.
;AL = midnight counter, advanced each time midnight passes.

;Notes:
;There are approximately 18.20648 clock ticks per second,
;and 1800B0h per 24 hours. 
;AL is not set by emulator yet! 
;----------------------
lablexxx:
mov ah,2
int 1ah

mov bl,ch
call bl_print
mov bl,cl
call bl_print
;------
push dx
push ax
mov ah,2
mov dl,'-'
int 21h
pop ax
pop dx
;------
mov bl,dh
call bl_print
mov bl,dl
call bl_print
;------
push dx
push ax
mov ah,2
mov dl,'-'
int 21h
pop ax
pop dx
;------
mov bl,al
call bl_print
;============
mov dh,0  ;DH = row. 
mov dl,0  ;DL = column.
mov ah,2  ;service
int 10h 
jmp lablexxx
;===========
;---------------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
; ============ sub bl_print ===========
bl_print PROC NEAR
push ax
push bx
push cx
push dx
;----------part 1
mov ah,2h
mov dl,bl  

mov cl,04h
shr dl,cl

add dl,30h

cmp dl,3ah
jl lable1

add dl,07h

lable1:
int 21h

; -----------part 2

mov dl,bl
and dl,0fh

add dl,30h

cmp dl,3ah
jl lable2

add dl,07h

lable2:
int 21h
;------------
pop dx
pop cx
pop bx
pop ax

ret ; return to where it was called
bl_print ENDP
;===================================

     end asli

حالا شد شبيه ساعت كامپيوتري. اگر دكمه full screen را در بالاي پنجره داسي بزنيد حركت سريع كرزر را بهتر مي بينيد.
 
آخرین ویرایش:

simona

New Member
من که دیگه کم آ وردم.:eek:
فقط اینجا اشتباهاتم را می گم:
اول اینکه از push و pop استفاده نکردم.هنوز هم دقیقا" دلیل استفاده از آنها را در این برنامه نمی دانم.
دوم اینکه از وقفه ی تغییر جای مکانما استفاده نکردم.فقط هر بار به خط بعدی می رفتم.
به این صورت که در قسمت data این کد را نوشتم
کد:
lf db 0dh,0ah,'$'
و در هر مرتبه که می خواستم به خط بعدی برم از این وقفه استفاده می کردم:
کد:
mov ah,9
lea dx,lf
int 21h
این بود که برنامه پیچیده شد. در واقع تغییر جای مکانما به برنامه نظم بیشتری داد.
راستی آقا سالک شما مطمئن هستید در حال یادگیری هستید؟:neutral:
باز هم ممنون
 

saalek110

Well-Known Member
سلام سايمون جان.
من از dh و dl استفاده كردم. و اين دو در دو حلقه خارجي و داخلي در حال افزايش هستند. و در cmp ها به راحتي از ين دو استفاده كردم. شما هم نياز داريد تا 2 رجيستر را در حلقه بيروني و حلقه دروني افزايش دهيد تا در عمق حلقه اين دو ابزار شما باشد. برنامه اي كه نستا براي رسم پيكسل ها نوشت هم ((حلقه اي تو در تو با cx و dx)) بود. در عمق حلقه نستا هم دو ابزار در اختيارش بود. ولي حلقه ((تو در تو فقط با cx )) اشكالش اينه كه در عمق حلقه ما به cx بيروني دسترسي نداريم. چون با push و pop روي حلقه داخلي پل زده ايم.
پس نمي توانيم در عمق حلقه بفهميم كه الان در كدام رديف هستيم. مگر رجيستري را در حلقه بيروني افزايش دهيد تا در عمق حلقه از آن استفاده كنيد. اگر نخواهيد اين كار را بكنيد بايد برنامه را 3 قسمت كنيد. قسمتي كه رديف اول را مي كشد . برنامه اي كه وسط را مي كشد و برنامه اي كه رديف آخر ستاره ها را رسم مي كند.
شما با برنامه ((اينتر كننده)) بايستي رجيستري را هم افزايش بدهيد كه بدانيد چند بار اينتر كرده ايد.
البته اگر منظور شما را درست فهميده باشم.
= = = = = = = = = ==
اما راجع به push و pop ها:
ببينيد ما گاهي از مثلا dl در 10 جاي برنامه مي خواهيم استفاده كنيم. با اين push و pop ها ما برنامه را پارتيشن بندي مي كنيم. برنامه زير را ببينيد:
Mov ah,2

Mov dl,33

Int 21h

كه كاركتر مربوط به عدد 33 را چاپ مي كند. اگر وسطش يك خطي باشد مثل mov dl,54 يعني اين طوري:

Mov ah,2
Mov dl,33

Mov dl,54

Int 21h

خوب معلومه كه 54 را چاپ مي كند نه 33 را. حالا من دو طرف 54 مي ايم push و pop مي گذارم:
Mov ah,2
Mov dl,33

Push dx
Mov dl,54
Pop dx

Int 21h
حالا ديگه همان 33 چاپ ميشه نه 54 . چون من پل زده ام روي 54.
منظورم از پل اينه كه قبل دستور 54 مي آيم يك نسخه از dx (شامل dl ) را در پشته كپي مي گيرم و بعد خط 54 مي آيم از آن كپي دوباره dx را ترميم مي كنم.
من اينجا خلاصه كردم و گفتم چاپ 33 و 54 . مي دانيد كه اولا ما دو مبناي عدد دادن داريم 16 و 10 كه اگر به 16 مي خواهيد بدهيد بايد بعد عدد حرف اچ را بگذاريد و ثانيا از جدول اسكي بايد نگاه كنيد كه وقفه با ديدن 33 و 54 چه كاراكتري را چاپ مي كند.
= = == = = = =
تمام زيربرنامه ها بايد رجيسترهايي را كه دستكاري مي كنند را push و pop كنند. مگر اين كه با يك رجيستر بخواهند خروجي بفرستند به برنامه اصلي كه او را صدا كرده. در اين مورد هم فقط آن رجيستر را باز مي گذاريم و بقيه را push و pop مي كنيم.

نكته مهم: آدرس برگشت زيربرنامه به برنامه اصلي ،يعني شماره خط آن خط كه بلافاصله بعد خطي قرار دارد كه دستور call داخلشه ، در پشته نگهداري ميشه. پس قبل رسيدن به دستور ret يعني بازگشت به برنامه اصلي بايد پشته را خالي كنيد.

براي راحتي اين طور مي شود گفت كه داخل هر زيربرنامه (يا برنامه اصلي) هر چيزي را كه push كرده ايد ، داخل همان زيربرنامه pop كنيد.
اين طوري استفاده شما از پشته با استفاده خود cpu از پشته تداخل نخواهد كرد.
 
آخرین ویرایش:

saalek110

Well-Known Member
در صفحات 4 و 5 و 6 تاپيك داشتيم از يك سايت كه در 7 صفحه آموزش داده بود تمرين مي كرديم و صفحه 5 آن سايت را نگفتيم.
آدرس سايت:
http://burks.brighton.ac.uk/burks/language/asm/asmtut/asm1.htm

آدرس صفحه 5 آن:
http://burks.brighton.ac.uk/burks/language/asm/asmtut/asm6.htm

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


2ymyd75.gif


کد:
.model small
.stack
.code 

mov ax,@data ; base address of data segment
mov ds,ax ; put this in ds

mov dx,OFFSET FileName ; put address of filename in dx 
mov al,2 ; access mode - read and write
mov ah,3Dh ; function 3Dh -open a file
int 21h ; call DOS service

mov Handle,ax ; save file handle for later
jc ErrorOpening ; jump if carry flag set - error!

mov dx,offset Buffer ; address of buffer in dx
mov bx,Handle ; handle in bx
mov cx,100 ; amount of bytes to be read
mov ah,3Fh ; function 3Fh - read from file
int 21h ; call dos service

jc ErrorReading ; jump if carry flag set - error! 

mov bx,Handle ; put file handle in bx 
mov ah,3Eh ; function 3Eh - close a file
int 21h ; call DOS service

mov cx,100 ; length of string
mov si,OFFSET Buffer ; DS:SI - address of string
xor bh,bh ; video page - 0
mov ah,0Eh ; function 0Eh - write character

NextChar:

lodsb ; AL = next character in string
int 10h ; call BIOS service
loop NextChar

mov ax,4C00h ; terminate program 
int 21h 

ErrorOpening:

mov dx,offset OpenError ; display an error 
mov ah,09h ; using function 09h
int 21h ; call DOS service
mov ax,4C01h ; end program with an errorlevel =1 
int 21h 

ErrorReading:
mov dx,offset ReadError ; display an error 
mov ah,09h ; using function 09h
int 21h ; call DOS service
mov ax,4C02h ; end program with an errorlevel =2 
int 21h

.data
Handle DW ? ; to store file handle 
FileName DB "C:\test.txt",0 ; file to be opened
OpenError DB "An error has occured(opening)!$"
ReadError DB "An error has occured(reading)!$"
Buffer DB 100 dup (?) ; buffer to store data

END

خيلي برنامه جالبي است. و علاوه بر خواندن فايل نكات ديگري هم دارد. يكي از نكاتش اينه كه 3 بار دستور خروج در آن بكار رفته اولي اين است:
mov ax,4C00h ; terminate program
int 21h

كه يك دستور خروج ساده است.
و دومي و سومي:
mov ax,4C01h ; end program with an errorlevel =1
int 21h
= = = = = =
mov ax,4C02h ; end program with an errorlevel =2
int 21h
مي بينيد كه 4c00 نيست و اعداد يك و دو در آن هست. يعني دارد به سيستم خطا را هم اعلام مي كند. البته من نمي دونم سيستم الان هم براش مهم است اين خطا ها يا فقط قديم در زمان dos مهم بوده. كلا من بحثي فعلا برايش ندارم.

حالا اين چند خروجي داشتن از اين لحاظ براي من جالب بود كه :
در برنامه مي بينيد كه برنامه در دستور خروج اول كارش تمام شده و در دستور خروج پايان مي يابد. اين طوري كدهاي بعدي كه كارشان چاپ پيغام خطا است در دسترس نيست و نمي خواهد جامپ كنيم از رويش و خيلي كار راحت تره.

اما برويم انتهاي برنامه راتوضيح بدهيم. يعني اينجا را:
.data
Handle DW ? ; to store file handle
FileName DB "C:\test.txt",0 ; file to be opened
OpenError DB "An error has occured(opening)!$"
ReadError DB "An error has occured(reading)!$"
Buffer DB 100 dup (?) ; buffer to store data

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

= = = = == == ==
حالا برويم از اول فايل توضيح بدهيم:

دو خط اول كه تنظيم قطعه داده است و به كرات استفاده شده و توضيح نياز ندارد. يعني اين قسمت:
mov ax,@data ; base address of data segment
mov ds,ax ; put this in ds
قسمت بعدي يعني اين قسمت:
mov dx,OFFSET FileName ; put address of filename in dx
mov al,2 ; access mode - read and write
mov ah,3Dh ; function 3Dh -open a file
int 21h ; call DOS service

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

در زير ورودي و خروجي سرويس باز كننده فايل كه يكي از سرويس هاي وقفه 21 است را با هم مي بينيم:
کد:
INPUT: 

AH = 3Dh 
AL = bits 0-2 Access mode 
000 = read only 
001 = write only 
010 = read/write 
bits 4-6 Sharing mode (DOS 3+) 
000 = compatibility mode 
001 = deny all 
010 = deny write 
011 = deny read 
100 = deny none 
DS:DX = segment:offset of ASCIIZ pathname 

OUTPUT: 

CF = 0 function is succesful 
AX = handle 
CF = 1 error has occured 
AX = error code 
01h missing file sharing software 
02h file not found 
03h path not found or file does not exist 
04h no handle available 
05h access denied 
0Ch access mode not permitted

توضيح:
اول شماره سرويس را در ah قرار مي دهيم كه 3d است.
ميشه شماره سرويس را هم جزو ورودي ها دانست البته.
بعد al را تنظيم مي كنيم. مي دانيد كه al داراي 8 بيت است.
3 بيت اول براي نوع دسترسي است(بيت ها را از سمت راست مي خوانند) كه شماره هاي صفر و يك و دو براي ((فقط خواندن)) ((فقط نوشتن)) و ((خواندن و نوشتن)) است. در برنامه ما در al 2 گذاشته ايم يعني هم خواندن و هم نوشتن.

بيتهاي شماره 4 تا 6 درون al براي Sharing mode است كه من فعلا نمي دانم چيه.
مي دانيد كه بيت اول 1 است و بعدي 2 و بعدي 4 و بعدي 8 . پس بيتهاي صفر تا 7 را اينطوري برويد بالا. مثلا اگر بيت اول روشن باشه و آخري ميشه 1 بعلاوه 128 كه ميشه 129 . البته در مبناي 10 است اين عدد.
براي مبناي 16 مي توانيد 4 بيت 4 بيت در نظر بگيريد.
در مورد 129 . در بيتهاي 0 تا 3 داريم ((يك –صفر- صفر-صفر))
و در بيتهاي 4 تا 7 داريم (( صفر-صفر – صفر – يك)) كه اين 4 بيت را باز اين طوري بخوانيد ((يك – دو – چهار – هشت)) پس ما 8 داريم در 4 بيت دوم و يك داريم در 4 بيت اول كه ميشه 81 در مبناي 16.

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

= == = = = =
حالا خروجي ها:
دو حالت دارد. يكي اينكه كار موفقيت آميز بوده . يعني فايل باز شده كه هندل در ax قرار مي گيرد. حالا مي گيم هندل چيه.
در حالت موفقيت آميز فلاگ cf صفر است.

حالت بعدي شكست در باز كردن فايل است كه فلاگ cf يك مي شود و كد خطا در ax قرار مي گيرد.
حالا اينكه هر كد چه معني ئي دارد اينهاست:
01h missing file sharing software
02h file not found
03h path not found or file does not exist
04h no handle available
05h access denied
0Ch access mode not permitted
كه خودتان ترجمه كنيد. اطلاعات من در اين مورد بيشتر از شما نيست.

اما در اينجا كه بالا گفته:
DS:DX = segment:eek:ffset of ASCIIZ pathname
يعني چه؟
اين ASCIIZ را مي گويم يعني چه؟
جواب: در كدهاي نمونه برنامه ، در قسمت تعريف متغيرها در قسمت داده ها ، 3 متغير رشته اي تعريف شده. يعني اينها:
FileName DB "C:\test.txt",0 ; file to be opened
OpenError DB "An error has occured(opening)!$"
ReadError DB "An error has occured(reading)!$"

مي بينيد كه دو تاي آخري كه براي چاپ يك پيغام است با علامت دلار پايان يافته. و قبلا هم من گفتم كه مواظب باشيد در پايان رشته هاي براي چاپ اين علامت دلار را يادتان نرود چون ((نشانه پايان رشته)) است و اگر نباشه همين طوري رشته به خواندن ادامه داده ميشه تا بطور اتفاقي يك دلار پيدا بشه و بياستد.
ولي 3 خط كد بالا ، اولي كه مسير فايل است با دلار خاتمه نيافته بلكه با ((صفر )) خاتمه پيدا كرده. به اين ASCIIZ مي گويند. كه يك صفر تهش داره. صفر كه مي دونيد ميشه zero .
و اون يكي اسكي (ASCII ) بدون z بود و با دلار خاتمه مي يابد.

حالا برسيم به هندل:
هندل خروجي سرويسه كه در ax ريخته مي شود و در خط زير:
mov Handle,ax ; save file handle for later

درون متغير ريخته ميشود. متغير هم word گرفته شده تا اندازه ax باشه.
در سايت گفته براي نگهداري آن ميشه از رجيستر هم استفاده بشه ولي اين جوري يكي همش بايد يادمان باشه كه هندل توي اونه و ديگري اين كه اون رجيستر اشغال مي مونه و نميشه ازش براي كارهاي ديگه استفاده كرد.

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

خط بعدي:
jc ErrorOpening ; jump if carry flag set - error!
اين هم يك پرش شرطي كه احتمالا به فلاگ cf نگاه مي كند. چون در اين برنامه و آموزش كه حرفي از فلاگ ديگري نبوده.

خوب نتيجه open فايل چي شد؟ شد يك هندل كه ريختيم در يك متغير و داريمش.
حالا برويم بقيه كدها را بخوانيم.

اين كد:
mov dx,offset Buffer ; address of buffer in dx
mov bx,Handle ; handle in bx
mov cx,100 ; amount of bytes to be read
mov ah,3Fh ; function 3Fh - read from file
int 21h ; call dos service

اول راهنماي ورودي و خروجي اين سرويس:
کد:
INPUT: 

AH = 3Fh 
BX = handle 
CX = number of bytes to be read 
DS:DX = segment:offset of a buffer 

OUTPUT: 

CF = 0 function is successful 
AX = number of bytes read 
CF = 1 an error has occurred 
05h access denied 
06h illegal handle or file not opened

اول شماره سرويس كه 3f است.
بعد هندل است كه بايد در bx وجود داشته باشد.
در cx هم تعداد بايتهايي كه بايد خوانده شود. ديگه شمارشگر بودن cx را خوب حس كرديم.

قضيه بعدي در كد برنامه ما اين:
mov dx,offset Buffer ; address of buffer in dx
است.
يعني كه ما آدرس بافر را مي دهيم تا هر چي از فايل خوانده شود برود داخلش.
از فايل به بافر. از هارد به ram (در قطعه داده).

حالا خروجي سرويس:
اول فلاگ cf است كه باز اگر صفر بود يعني كار خوانده موفقيت آميز بوده و در اين حالا تعداد بايتهاي خوانده شده در ax منعكس مي شود ،
و اگر عمل با شكست مواجه شود ، cf آنگاه (( يك)) خواهد شد.
و اينها:
05h access denied
06h illegal handle or file not opened
احتمالا ميرود داخل ax . من اينجا را نفهميدم.
در ادامه توضيحات سايت گفته كه اگر cf صفر شد و ax هم صفر بود ، يعني كه به اشاره گر به انتهاي فايل رسيده و بيشتر از اين نميشه خواند.
منظور از اشاره گر اينه كه وقتي از داخل فايل چيزي خوانده ميشه ، ميره خط بعد تا خط بعدي خوانده شود.
و اگر cf صفر بود و ax كوچكتر از cx بود ، يعني كه قسمتي از فايل خوانده شده و كار متوقف شده كه يا به علت رسيدن به انتهاي فايل بوده يا به علت رخ دادن خطايي.
اين چند خط توضيح را با اين :
05h access denied
06h illegal handle or file not opened
فكر كنم بشه يك جورايي با هم جمع كرد. خودتان تحقيق كنيد. من هم اگر جايي بود كه بهتر توضيح داده بود مي گويم.

برويم قسمت بعدي برنامه امان:
mov bx,Handle ; put file handle in bx
mov ah,3Eh ; function 3Eh - close a file
int 21h ; call DOS service

اين هم سرويس ديگري است كه 3e است و باز هندل مي خواهد . كارش هم بستن فايل است.
اين هم ورودي و خروجي اين سرويس:
کد:
INPUT: 

AX = 3Eh 
BX = file handle


OUTPUT: 

CF = 0 function is successful 
AX = destroyed 
CF = 1 function not successful 
AX = error code - 06h file not opened or unauthorised handle.

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

خوب. خسته نباشيد.
 
آخرین ویرایش:

جدیدترین ارسال ها

بالا