در صفحات 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 در درايو سي بسازيد. يك بار هم بي فايل اجرا كنيد تا خطا را دريافت كنيد.
کد:
.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
![Big Grin :D :D](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
X = segment
![Eek! :eek: :eek:](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
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 كرده ايد و ديگر هيچ چيزي نمي توانيد وارد كنيد.
خوب. خسته نباشيد.