loading...
دانلود سرای دانشجویی

ارسال و دريافت پارمترها

پارامترها مقاديری هستند که می توانيد به زيربرنامه بدهيد يا بگيريد. برای ارسال يا دريافت پارامترها معمولا از ثبات، متغيرهای سراسری يا پشته استفاده می شود.

ارسال پارامتر از طريق ثبات

مثال. زيربرنامه زير طول يک رشته را محاسبه و در ثبات CX برمیگرداند. آدرس شروع رشته در ثبات SI قرار دارد.

StrLen PROC
           push SI
           mov CX,0
Whl:   cmp Byte Ptr[SI],'$'
           jc EndW
           inc CX
           inc SI
           jmp Whl
EndW: pop SI
           ret
StrLen ENDP

ارسال پارامتر از طريق پشته

پارامترهائی که به زيربرنامه داده می شوند را می توان قبل از فراخوانی زيربرنامه در پشته اضافه کرد. پارامترها در زيربرنامه pop نمی شوند بلکه مستقيما از پشته دسترسی می شوند زيرا قبل از دستور call در پشته اضافه شده اند و آدرس برگشتی بعد از آن اضافه می شود. علاوه براين چون ممکن است در چندين جای زيربرنامه استفاده شوند معمولا درون ثبات نگهداری نمی شوند و بهتر است در حافظه پشته باقی بمانند.

يک برنامه خارجی که يک پارامتر از طريق پشته را ارسال می کند در نظربگيريد. وقتی زيربرنامه درخواست می شود پارامتر می تواند با آدرس دهی غيرمستقيم [SP+4] دسترسی شود. اگر پشته هم در زيربرنامه برای ذخيره داده استفاده شود عدد بيشتری بايد به SP اضافه شود. ثبات BP را برای ارجاع به داده های درون پشته می توان به کار برد. ثبات SP با هر push و pop تغيير می کند اما BP ابتدا برابر با SP می شود و سپس ثابت می ماند در انتهای زيربرنامه مقدار اوليه BP بايد برگردانده شود. بعد از اينکه زيربرنامه تمام شد پارامترهائی که در پشته اضافه شده اند بايد حذف شوند.


مثال. تابع زير طول رشته را محاسبه و آدرس شروع رشته از طريق پشته به زيربرنامه ارسال می شود.

StrLen PROC
           push BP
           mov BP,SP
           mov SI,[BP+4]
           sub CX,0
Whl:   cmp byte ptr [SI],'$'
           jc Endw
           inc CX
           inc SI
           jmp Whl
EndW: pop BP
           ret
StrLen ENDP

مثال. محاسبه مجموع سه عدد که از طريق پشته به زيربرنامه ارسال شده اند

دستورات فراخوانی و بازگشت زيربرنامه

دودستورالعمل که پشته را استفاده می کنند و فراخوانی و برگشت زيربرنامه را انجام می دهند call و ret هستند. برای هدايت کنترل اجرا به زيربرنامه بايد آنرا فراخوانی کرد. زيربرنامه ها در هر کجای برنامه که به آن نياز داريم با دستور call فراخوانی می شوند. دستور call به صورت زير است:

call ProcedureName

دستورالعمل call باعث يک پرش غير شرطی به زيربرنامه می شود و آدرس دستورالعمل بعدی را در پشته ذخيره می کند. CPU در برخورد با دستور call به آدرس شروع زيربرنامه رجوع می کند و دستورات آنرا اجرا می نمايد. با برخورد به دستور ret به برنامه فراخوان بر می گردد و دستورات بعد از call را اجرا می نمايد.


مثال. فراخوانی زيربرنامه Putc.

call Putc

CPU در برخورد با دستور Call عمليات زير را انجام می دهد:

فراخوانی از نوع داخلی

1. مقدار ثبات IP (که حاوی آدرس دستور بعد از call است ) را در پشته ذخيره می کند.
2. آدرس ذکر شده مقابل دستور call را در ثبات IP قرار می دهد.

فراخوانی از نوع خارجی

1. مقدار ثبات CS را در پشته ذخيره می کند.
2. بخش سگمنت آدرس ذکر شده مقابل دستور call را در ثبات CS قرار می دهد.
3. مقدار ثبات IP را در پشته ذخيره می کند.
4. بخش آفست آدرس ذکر شده در جلوی دستور call را در ثبات IP قرار می دهد.

دستورالعمل ret آدرس ذخيره شده IP را از پشته بر می دارد و به برنامه اصلی بر می گردد. CPU در برخورد با دستور Ret عمليات زير را انجام می دهد:

بازگشت از زيربرنامه داخلی

1. مقدار ذخيره شده در پشته را در داخل ثبات IP قرار می دهد.

بازگشت از زيربرنامه خارجی

1. مقدار ذخيره شده در پشته را در داخل ثبات IP قرار می دهد.
2. مقدار ذخيره شده در پشته را در داخل ثبات CS قرار می دهد.

نکته. اگر دستور ret در انتهای زيربرنامه حذف شود کنترل اجرای برنامه به زيربرنامه بعدی می رود نه دستورالعمل بعدی در برنامه اصلی.
نکته. معمولا در ابتدای هر زيربرنامه بهتر است مقادير ثبات هائی که تغيير می کنند را در پشته ذخيره نمائيم و در انتهای زيربرنامه و قبل از دستور ret مقادير آنها را از پشته بازيابی کنيم. بايد توجه کنيم که دستورات pop متناظر با دستورات push باشند و کليه داده هائی که در زيربرنامه در پشته push شده اند بايد pop شوند وگرنه به با دستور ret به آدرس درست پرش نمی کند.


مثال. زيربرنامه برای نمايش 40 کاراکتر space. توجه کنيد زيربرنامه Putc درون زيربرنامه PrintSpaces فراخوانی شده است.

PrintSpaces PROC near
                push AX
                push CX
                mov AL, ' '
                mov cx, 40
PSLoop:   call putc
                loop PSLoop
                pop CX
                pop AX
                ret
PrintSpaces ENDP

در ابتدای زيربرنامه ثبات های AX و CX در پشته قرار می گيرند و در انتها به ترتيب عکس بازيابی می شوند. زيربرنامه فوق به صورت زير فراخوانی می شود.

call PrintSpaces

 

دو نوع زيربرنامه وجود دارد داخلی (intrasegment) و خارجی (intersegment).

• زيربرنامه های داخلی در همان سگمنتی که تعريف شده اند قابل فراخوانی هستند و در تعريف آنها از صفت near استفاده می شود.
• زيربرنامه های خارجی روال هائی که در سگمنت ديگری قرار دارند و از ساير سگمنت ها قابل فراخوانی می باشند و در تعريف آنها از صفت far استفاده می شود. زيربرنامه های خارجی درفايل جداگانه ای قرار دارد و هنگام لينک کردن بايد به برنامه پيوند داده شوند. نتيجه کار بعد از لينک مانند زيربرنامه داخلی است.

فراخوانی از نوع near کنترل را درون همان سگمنت کد جابجا می کند وتنها مقدار IP در پشته ذخيره می شود. فراخوانی far کنترل را بين سگمنت های مختلف عبور می دهد. هر دو مقادير CS و IP در پشته قرار می گيرند.

نکته. دستورات call و ret نوع فراخوانی را مشخص نمی کنند بلکه عملوند near|far راهنمای proc به اسمبلر می گويد فراخوانی از کدام نوع است.

زير برنامه (procedure) مجموعه ای از دستورات است که يکبار تعريف و به دفعات استفاده می شود. با بکارگيری زيربرنامه خوانائی برنامه بالاتر رفته و از تکرار دستورات مشابه جلوگيری می شود. علاوه براين اشکال زدائی و تغيير برنامه آسان تر انجام گيرد.

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


تعريف زيربرنامه

تعريف زيربرنامه بايد در سگمنت کد انجام بگيرد. از دو راهنمای proc و endp برای تعيين بلاک زيربرنامه استفاده می شود.

ProcedureName PROC [NEAR|FAR]
     ...
     RET
ProcedureName ENDP

Procedurename نام زيربرنامه است که قبل از راهنماهای proc و endp قرار می گيرد و بايد يکسان باشد. عملوند near يا far اختياری است. کلمه near به اسمبلر می گويد که زيربرنامه از نوع داخلی است. برای تعريف يک زيربرنامه خارجی از کلمه far به جای near استفاده می شود.

دستور ret باعث خروج از زيربرنامه و برگشت به فراخواننده می شود.


نکته. اگر عملوندی مقابل تعريف زيربرنامه قرار نگيرد از نوع near در نظر گرفته می شود.
نکته. اگرچه تعريف يک زيربرنامه که عملا داخلی است به صورت خارجی اشکالی ايجاد نمی کند ولی بهتر است اين کار را نکنيد.


مثال. زيربرنامه جمع دو عدد در AH و AL و نگهداری مجموع در ثبات BX.

Adding PROC near
     mov BX, AL
     add BX, AH
     ret
Adding ENDP

مثال: زيربرنامه Putc برای نمايش کاراکتری که در ثبات al قرار دارد.

Putc PROC
     mov DL,AL
     mov AH,02
     int 21h
     ret
Putc ENDP

تبديل نوع

کامپايلر به طور خودکار يک نوع داده را درصورت نياز به ديگری تبديل می کند. مثلا اگر يک عدد int در متغير float ذخيره شود کامپايلر مقدار را به float تبديل می کند. هميشه نوع کوچکتر به نوع بزرگتر تبديل می شود. اگر يک عدد float با double جمع شود با هردو به عنوان double برخورد می شود.

اگر سعی کنيد مقدار بزرگتری را در متغير کوچکتر ذخيره کنيد بخشی از داده ممکن است از دست برود و احتمالا با يک پيغام هشدار مواجه خواهيد شد.


مثال.

char a='2';
int b= a+ 9;

const int big=110232343;
const short int small=big;


اگر برنامه نويس بخواهد صريحا عمل تبديل نوع را انجام دهد از casting استفاده می کند. برای اين کار نوع داده مورد نظر را درون پرانتز سمت چپ مقدار قرار دهيد. مقدار می تواند متغير، ثابت،‌ حاصل يک عبارت يا مقدار برگشتی يک تابع باشد.


مثال.

int b = 200;
unsigned long a = (unsigned long int)b;


در C++ راه ديگری هم برای تبديل نوع وجود دارد. در اين روش مانند فراخوانی توابع پرانتز اطراف مقدار قرار می گيرد.

مثال.

float a = float(200);
// This is equivalent to:
float b = (float)200;

البته در مثال فوق نوشتن 200f به تنهائی کفايت می کند.

ثبات SP

ثبات های SS و SP به پشته به صورت SS:SP به پشته اشاره می کنند. در هنگام اجرای يک برنامه EXE ثبات SS توسط سيستم عامل برابر آدرس سگمنتی که پشته را در بردارد و ثبات SP برابر آفست بالای پشته می شود. يعنی آدرس جائی از پشته که داده بايد برداشته شود.

پشته به صورت معکوس در حافظه رشد می کند(يعنی به سمت آدرس های کمتر). وقتی يک کلمه در پشته اضافه می شود در آدرس SS:SP ذخيره می شود و از SP دو واحد کم می شود. دستور push مقدار SP را کاهش و دستور pop مقدار SP را افزايش می دهد.

هنگامی که يک کلمه در پشته push شود عمليات زير توسط CPU انجام می شود:

1. دو واحد از ثبات SP کم می شود.
2. کلمه مورد نظر در آدرس SS:SP کپی می شود.

هنگامی که يک کلمه از پشته pop شود عمليات زير توسط CPU انجام می شود:

1. از آدرسSS:SP يک کلمه خوانده می شود.
2. دو واحد به ثبات SP اضافه می شود.


مثال. فرض کنيد مقدار اوليه SP برابر با 1000h است.

push word 1 ;1 stored at 0FFEh, SP = 0FFEh
push word 2 ;2 stored at 0FFCh, SP = 0FFCh
push word 3 ;3 stored at 0FFAh, SP = 0FFAh
pop AX ;AX = 3, SP = 0FFCh
pop BX ;BX = 2, SP = 0FFEh
pop CX ;CX = 1, SP = 1000h


هنگام فراخوانی زير برنامه توسط دستور call مقدار ثبات های CS و IP که به دستورالعمل بعدی اشاره می کنند در پشته ذخيره می شود. هنگامی که CPU در زير برنامه به دستور ret می رسد مقادير را از پشته حذف و به ثبات های CS و IP برمی گرداند.


مثال. شکل زير وضعيت پشته را قبل و بعد از انجام دستور Call 3C10:0720 نشان می دهد.

اسمبلی

دستورات push و pop

دستورات push و pop دستورات پايه برای استفاده از پشته هستند. برنامه نويس اسمبلی از طريق دستورات زير می تواند داده های خود را در پشته قراردهد و يا از پشته بردارد. فرم کلی دستورات به صورت زير است:

push mem/reg
pop   mem/reg

push عملوند خود را به پشته اضافه می کند و دستور pop مقداری را از پشته حذف می کند و در عملوند خود قرار می دهد. داده ای که برداشته می شود هميشه آخرين داده ای است که اضافه شده است.

عملوند دستورات push و pop نمی توانند فوری يا ثبات های CS و IP و flag باشند.


مثال 1. دستورات زير يک کلمه را در پشته قرار می دهد.

mov AX, 12
push AX

مثال 2. دستورات زير محتوای دو متغير Value و Count را با هم تعويض می نمايد.

push Value
push Count
pop Value
pop Count

مثال 3. به کمک دستورات پشته می توان محتوای يک ثبات سگمنت را در ديگری کپی کرد.

push DS
pop CS

مثال 4. مقدار نهائی AX برابر با 1234h است. ابتدا در AX عدد 1234h ذخيره می شود سپس وقفه فراخوانی می شود. مقدار AX از پشته بازيابی می شود.

mov AX,1234H
push AX
mov AH,09
int 21H
pop AX

تعريف ماکرو

تعريف ماکرو توسط برنامه نويس و با استفاده از راهنمای macro صورت می گيرد. فرم کلی تعريف ماکرو به شکل زير است:

MacroName MACRO [parameter1, parameter2...]
     ...
MacroName ENDM

تعريف ماکرو با راهنمای macro شروع و با راهنمای endm پايان می پذيرد. نام ماکرو قبل از هر دو راهنمای بايد يکسان باشد.

در ماکرو، برخلاف زيربرنامه، ارسال پارامتر امکان پذير است.


مثال. تعريف ماکرو ExitPgm برای خروج از برنامه و برگشت به محيط سيستم عامل.

; ExitPgm- Returns control to MS-DOS
ExitPgm MACRO
     mov AH, 4ch
     int 21h
ExitPgm ENDM

مثال. ماکرو که مکان نما را به موقعيت داده شده منتقل می کند.

Position MACRO Row, Column
     push AX
     push BX
     push DX
     mov AH, 02H
     mov DH, Row
     mov DL, Column
     mov BH, 0
     int 10H
     pop DX
     pop BX
     pop AX
Position ENDM


برای استفاده از ماکرو تنها کافی است نام آنرا مشابه هر دستور ديگری فراخوانی کنيم. فراخوانی ماکرو مانند زيربرنامه نيازمند دستور call نيست.

ماکرو فوق به صورت زير فراخوانی می شود.

Position 8, 6

ماکرو مجموعه ای از دستورات است که مشابه زيربرنامه يکبار نوشته می شود و چندين بار استفاده می شود.


ماکرو (macro) نام مخففی برای مجموعه ای از دستورالعمل ها، راهنماها يا ماکروهای ديگر است که يکبار نوشته می شود و به هر تعداد دفعات لازم قابل استفاده است.

اسمبلر هنگام ترجمه برنامه در مواجهه با نام ماکرو دستورات معادل را قرار می دهد.

اسمبل و اجرای برنامه

برای ايجاد برنامه به سه ابزار نياز است: يک اديتور متن، يک اسمبلر برای تبديل برنامه به فايل مقصد و يک لينکر برای توليد فايل اجرائی.

برنامه اسمبلی را در يک اديتور متن نوشته و با پسوند .asm ذخيره کنيد. فراموش نکنيد که حتما از يک اديتور اسکی استفاده کنيد. توسط اسمبلر (masm.exe يا tasm.exe) از فايل مبدا .asm فايل مقصد .obj را ايجاد کنيد. اسمبلر برنامه زبان اسمبلی را به کد ماشين تبديل می کند. اگر خطائی در برنامه وجود داشته باشد اسمبلر خطا را گزارش می دهد. لينکر (link.exe يا tlink.exe) از يک يا ترکيب چند فايل .obj يک برنامه قابل اجرا از نوع .exe يا .com را می سازد.


مثال. برنامه first.asm را در اديتور متن ذخيره کنيد. سپس در خط فرمان سيستم عامل، در محلی که اسبلر نصب شده است، دستورات زير را به ترتيب وارد کنيد تا فايل اجرائی first.exe ايجاد شود.

C:masm>masm first
C:masm>link first
C:masm>first


مثال: در برنامه زير دو عدد با هم جمع می شود.

        .MODEL small
        .STACK [size]
        .DATA
number1 DW 0800h   ;=128
number2 DW ffebh    ;=-493
sum         DW ?            ;store result

        .CODE
begin:
   mov AX,@Data
   mov DS,AX
   mov AX,number1 ;get first number in AX
   add AX,number2  ;add AX with second number
   mov sum,AX      ;store result in Sum
   mov AX,4c00h
   int 21h
END begin

مثال: تکه برنامه زير اعداد 1 تا 10 را در آرايه ای از نوع word ذخيره می نمايد.

        .MODEL small
        .STACK [size]
        .DATA
Array DW 10 dup(?)
        .CODE
begin:
   mov AX,@Data
   mov DS,AX
   mov CX,1
   mov SI, offset Array
Forl:
   mov [SI], CX
   inc SI
   inc SI
   cmp CX,10
   je endf
   inc CX
   jmp forl
Endf:
   mov AX,4c00h
   int 21h
END begin

برای دسترسی به عناصر آرايه معمولا از عملوند غيرمستقيم ثباتی استفاده می شود. برای تخصیص آدرس آفست يک آرايه می توان از دستور LEA هم استفاده کرد. دقت کنيد چون عناصر آرايه دو بايتی هستند هربار دو واحد به SI اضافه می شود. در حالتی که عناصر آرايه از نوع بايت تعريف می شوند به اشاره گر آرايه يک واحد اضافه می شود.

مثال: کاراکتر * را نمايش می دهد.

        .MODEL small
        .STACK [size]
        .CODE
main PROC
   mov AH,2h
   mov DL,2ah
   int 21h
   mov AX,4c00h
   int 21h
main ENDP
END main

تعداد صفحات : 425

اطلاعات کاربری
آمار سایت
  • کل مطالب : 4247
  • کل نظرات : 0
  • افراد آنلاین : 4
  • تعداد اعضا : 2926
  • آی پی امروز : 66
  • آی پی دیروز : 161
  • بازدید امروز : 405
  • باردید دیروز : 830
  • گوگل امروز : 6
  • گوگل دیروز : 51
  • بازدید هفته : 405
  • بازدید ماه : 35,346
  • بازدید سال : 110,455
  • بازدید کلی : 8,289,149
  • کدهای اختصاصی