برگزیده های پرشین تولز

اسمبلي براي سي

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
من وقتي به سراغ سي آمدم قصد نداشتم از اسمبلي دور بشوم. و چون محيط سي راحت تر از اسمبلي است ولي نزديك به اسمبلي ، ترجيح دادم در محيط سي كار كنم.

و چون بعد اين در تاپيك آموزش سي ++ از پايه بيشتر مي خواهم به سمت اسمبلي متمايل بشوم ، اين تاپيك را باز كردم تا اول يك پيش زمينه آشنايي با اسمبلي براي كساني كه با اسمبلي آشنا نيستند داده بشه و بعد من بتوانم راحت تر آنجا صحبت كنم.

ارتباط با ويندوز را هم مي گذاريم در ويژوال سي. و فعلا با ويندوز كاري نداريم.
به نقل از تاپيك : ((آي هوار ، برنامه نويسان دلفي هم دل دارند.))

به نقل از littlerabbit :
1. وي بي قابليت پردازش پيغام هاي Custome نداره. در صورتي كه تو دلفي اين كار مثل آب خوردنه و تو ويژوال سي اين كار اساس روش برنامه نويسي اونه.

البته ممكنه برداشت من از فرموده مديريت محترم اشتباه باشه ولي در ويژوال سي با پيغامها با ويندوز ارتباط برقرار مي كنيم. پيغام(مسيج) دريافت مي كنيم و مسيج مي فرستيم..

در كل من مي خواهم وقتي مي روم سراغ ويژوال سي ، ((اسمبلي و سي و ويژوال سي)) را با هم داشته باشيم.

در اين تاپيك نمي خواهيم اسمبلي كار بشويم . بلكه آن قسمتي كه در سي لازم است را پي مي گيريم.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
ما مي توانيم 3 جور اسمبلي كار كنيم:

روش اول : با همان برنامه debug ويندوز كار كنيم. كه بيشتر براي تمرين و آموزش خوبه.

روش دوم : فايل سورس اسمبلي توليد كنيم و با اسمبلر(كامپايلر) ها ، مثل masm و tasm و لينك كننده ها (linker ) به exe تبديل كنيم.

روش سوم : كدهاي اسمبلي خود را در دل كدهاي سي بنويسيم.

= == = == = == = == = == = == = == = == = == == == = == =

اما من بيشتر نظرم روي روش سوم است . چون ((اسمبلي در خدمت سي)) هدفم است.

= == = == = == = == = == == == == == == == == == = == = =

توضيح روش دوم: همان طور كه ما سورس c يا c++ را با پسوندهاي c و cpp ذخيره مي كنيم و از tc و link براي تبديل به exe استفاده مي كنيم ...

در اسمبلي هم سورس داريم كه پسوندش asm است و با masm و link تبديل به exe مي كنيم.

البته من از tasm استفاده مي كنم. چون كمتر error ميده.
و اصلا شما نياز نداريد كه tasm و masm را داشته باشيد ، چون ما قصد نداريم كه اسمبلي كار كنيم. ما با همان روش سوم كار مي كنيم. ولي من لينك دانلود اين ها را مي گذارم. خيلي هم كوچك هستند، تا كليك كنيد دانلود مي شوند. ولي چون من از كامپيوتر خودم آپلود كرده ام ، ممكنه ويروسي باشه و من پاسخ گوي ويروسي شدن كامپيوتر شما نيستم. با يك سرچ كوچك هم مي توانيد سريع پيدا كنيد آنها را در اينترنت. اگر كسي هم لينك داشت بگذارد.


من اين دو را داشتم. آپلود كردم.
tasm & link

ولي اگر ويروس ياب نداريد ، دانلود نكنيد.

http://assembly.250free.com/Link.exe
http://assembly.250free.com/Tasm.exe

روي هم 150 كيلو.
.

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

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
روش سوم:
كه با دو روش داره:

اول با استفاده از كلمه asm كه از كلمات كليدي سي نيست و از كلمات ((مايكروسافت سي)) است . و در توربو سي معتبر است.
دوم با همان union و استيل سي.


با استيل اسمبلي:​
کد:
[left]
#include <iostream.h>
#include <conio.h>


void main()
{
 clrscr();
cout<<"hello  "<<2+2<<endl;

asm{
mov ax,1
int 33h

   }

getch();
}


[/left]

با استيل سي :
کد:
[left]
#include <iostream.h>
#include <conio.h>
#include<dos.h>

void main()
{
 clrscr();
cout<<"hello  "<<2+2<<endl;

union REGS i,o;
  i.x.ax=1;
  int86(0x33,&i,&o);
getch();

}
[/left]

در برنامه بالا كه هر دو يكي است در حقيقت در قسمت سي فقط يك hello نوشته ايم و 2+2 و با اسمبلي ماوس را روشن كرده ايم.
.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
توضيح روش اول: يعني همون استفاده از debug .

اول يافتن debug در ويندوز كه با دو روش مي توانيد اين كار را بكنيد.


روش اول:

a1.gif


a2.gif




روش دوم:

a3.gif


a4.gif



در روش دوم با نوشتن كلمه debug وارد محيط آن مي شويم و و با زدن q خارج مي شويم.
وقتي خطي افقي مثل منها ميايد ، يعني در محيط ديباگ هستيم. من كلمه r را هم زدم تا ليست رجيسترهاي cpu به نمايش دربياد. كه بعدا رجيسترها را بحث مي كنيم. و يكي از اهداف اين تاپيك معرفي خوب آنهاست و طرز استفاده از آنها.
.
در شكل بالا تمامي رجيسترها در معرض ديد نيست چون من پنجره را كوچك كرده ام. 3 تا از سمت راست رفته بيرون.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها

a5.gif


به شكل بالا نگاه كنيد. ابتدا با r من ليست رجيسترها را گرفته ام. و مي بينيد كه ax و bx هر دو صفرند.
بعد با دستور a و اينتر ، آماده نوشتن كدها شده ام. 3 خط دستور نوشته ام و بعد در خط چهارم ، اينتر كرده ام تا از ((حالت دستور نويسي)) خارج شوم. بعد 3 بار حرف t را زده ام. T كارش اين است كه هر بار يك خط از دستورات ما را اجرا مي كند.
بعد t اول مي بينيد كه ax تغيير كرده. چون دستور mov باعث شده كه عدد 1111 به ax نسبت داده شود.
بعد t دوم مي بينيد كه bx تغيير كرده. به دليل قبلي.
بعد t سوم مي بينيد كه ax تغيير كرده . چون كه add باعث شده كه ax و bx جمع بشوند و در ax قرار بگيرند.
== == == == === == == === === === === === ===
البته من برنامه بالا را براي سرگرمي نوشتم. چون قراره كه ما محاسبات را در سي انجام بدهيم و براي چنين كارهايي به سراغ اسمبلي نرويم.
== == == == == == == == == == == === === ====
در شكل بالا ، چهار بار ليست رجيسترها به نمايش درآمده. اولي قبل اجراي هيچ دستوري و 3 بار بعد بعد اجراي دستورات ما.
به ip دقت كنيد. از 100 تا 108 تغيير كرده. و موقعي كه داشتيم دستور مي نوشتيم به آن اعداد قبل دستور نگاه كنيد. آنها هم مشابه ip تغيير كرده اند.
نتيجه گيري: ip آدرس جايي است كه دستور آماده اجرا آنجا در Ram نشسته. كنترل cpu به ip منتقل مي شود و آن دستور را اجرا مي كند.
پس در استفاده از حرف t دقت كنيد. چون اين دستور باعث ميشود كه كنترل برود دستور نشسته در آدرس ip را اجرا كند. پس بايد قبل استفاده از اين دستور ip را خودتان به شكل دستي تنظيم كنيد.
در تمرينات بالا من تنظيم نكرده ام . چون مي دانستم كه بعد هر t خودبه خود ip به دستور بعدي نشانه مي رود و من هم همين را مي خواستم . يعني مي خواستم بعد اجراي هر دستور ، دستور بعدي اجرا شود.
و حالا اگر بخواهم كار را تكرار كنم اول بايد دوباره ip را 100 كنم. براي اينكار

کد:
-r ip  ((inter))
ip 0100
: [color=red]_[/color]

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


a6.gif


در شكل بالا اول با r يك ليست گرفتيم. بعد با a باز وارد دستور نويسي شده ايم.
ولي اين بار بجاي t از حرف g استفاده كرديم.
تفاوتهاي t و g :

اولي يعني t فقط يك دستور را اجرا مي كند و متوقف مي شود و نتيجه را با نشان دادن رجيسترها در معرض ديد قرار مي دهد ولي دومي يعني g ، تا دستور خاتمه (كه در اينجا int 20 است) به اجراي متوالي دستورات ادامه مي دهد.

اولي هر تغييري در رجيسترها ايجاد شود را ره حالت اول برنمي گرداند ولي دومي بعد اينكه كارش تمام شد ، تمام رجيسترها (من جمله ip ) را به حالت قبلي در مي آورد.

حالا خودتان قضاوت كنيد كه هر يك به چه كاري ميايد.
= == = == == = == = == = == == == == ==
حالا شرح دستورات :
ما آمده ايم ah را 2 كرده ايم . و dl را 41 .
و بعد وقفه 21 را صدا زده ايم. وقفه 21 كه كار نداريم وقفه dos است يا bios ، هزار تا كار انجام مي دهد و چه طوري بهش بگيم الان كدام كارت را انجام بده؟؟
جواب : با تنظيم ah . با تغيير ah مي گوييم داريم از سرويسهاي فلان وقفه استفاده مي كنم. و اينجا داريم از سرويس 2 وقفه 21 استفاده مي كنيم. و اينجا كارش اينه كه dl را كد يك حرف در نظر مي گيره و آن را چاپ مي كند كه 41 همان كد حرف A است.

براي خروج هم از وقفه int 20 استفاده كرده ايم. كه اين وقفه كارش اينه كه كنترل را از برنامه ما مي گيره و به dos برمي گرداند و يكسري كارها هم انجام مي دهد كه حالا در سطح من نيست بگم.

خوب يك برنامه 4 خطي نوشتيم. حالا همين برنامه مي تواند تبديل به يك فايل com بشه و يادگاري براي خود نگه داريم تا هر وقت روي اين فايل كليك كنيم ، يك حرف a براي ما چاپ كنه. البته ضرورتي نداره كه اين كار را ياد بگيريم ولي براي سرگرمي من روش اين كار را مي گويم.
اول بايد اسمي به فايل بدهيد. كه بايد با پسوند بگيد. كه com است

کد:
-n saalek.com

بعد بايد حساب كنيد كه حجم فايل شما چقدر است و در cx قرار بدهيد(اگر بزرگ بود ، ادامه اش در bx ) . در شكل بالا جايي كه اينتر كرديم و از دستورنويسي خارج شديم ، نگاه كنيد ، ip مساوي 108 است . يعني ما از 100 شروع كرده ايم و تا 108 كد نوشته ايم . پس 8 ميشه حجم فايل ما . پس cx را مساوي 8 كنيد. با همان دستور قr . همون جور كه ip را تنظيم كرديد.

مي رسيم به مرحله آخر كار كه save است. البته بايد قبلش اسم داده باشيد و حجم فايل را تعيين كرده باشيد. براي save ، كافيه حرف w را بزنيد و اينتر كنيد.
در شكل زير همين مراحل را من انجام داده ام.


a7.gif


فايل شما روي desktop منتظر شماست. و حجمش 8 بايته.
شايد اين كوچكترين برنامه اي باشه كه مي شد ساخت كه كاري انجام مي دهد!!


a8.gif


اين تمرينات ساده را كرديم تا فقط با رجيسترها و مقدار دهي به آنها مانوس بشه ذهنمان و كار با وقفه.
دليلي به انجام اين تمرينات از سوي شما نيست. فقط مي خواستم بدانيد كه رجيسترها چه هستند و وقفه چه طوري احضار ميشه.
در تاپيك اصلي هم از وقفه 33 براي روشن كردن ماوس استفاده كرديم ولي با استيل سي نه با استيل اسمبلي.
يك هدف من از نوشتن اينها اينه كه يكسري رجيستر خاص را بعدا مي خواهم بكار ببرم كه كارهاي خاصي انجام مي دهند.

به اسامي رجيسترها نگاه كنيد. يكسري با حرف s ختم مي شوند شامل cs و ds و ss و es . اينها مربوط به آدرس قطعه ها هستند. مثلا cs:ip ميشه آدرسي كه كنترل به آنجا ميره براي اجراي دستور آنجا. مثل آدرس خيابان و كوچه است. Ip ميشه كوچه و cs خيابان.

قطعه پشته هم با ss و sp معين ميشه. دقيقا مثل cs:ip . داريم ss:sp . كه sp ميشه stack pointer كه فكر كنم نشان مي دهد تا كجا پشته پر شده. كه فعلا چون كتاب جلوم نيست مطمئن نيستم. bp هم شايد با پشته مربوط باشه. فعلا قسمتهايي كه راجع به ادرسهاي پشته گفته شد را با شك بخوانيد تا بعدا بيام اصلاح كنم. ولي بعدا اگر لازم شد درست تر و كامل تر بحث مي كنيم.
اين كه مي گم اگر لازم شد به اين خاطره كه تا آنجايي كه ميشه ، من مي خواهم از دستورات اسمبلي در تاپيك اصلي استفاده نكنم و اگر كار در محيط اسمبلي كمك كننده بود ، آنگاه به اين سمت(اسمبلي) متمايل مي شوم. پس اگر با دستورات سي ، بشه پشته را آموزش داد و استفاده كرد ، سراغ اسمبلي نمي آيم و آنوقت اين تاپيك فقط جهت يك آشنايي و سرگرمي مطرح است.

راجع به si و di هم كاربرد خوبي داره براي نوشتن و خواندن در Ram . كه با ds و es تركيبي كار مي كنند. يعني قضيه كوچه و خيابان ، هميشه براي Ram مطرحه.

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

====================================

ديباگ قادر است كه فايل com شما را دوباره بخواند. به محيط ms dos prompt برويد و به جايي كه فايل com شما قرار دارد برويد و مثل شكل زير اقدام كنيد. حرف u ليست دستورات را مي دهد كه مي بينيد همان دستوراتي است كه شما نوشته ايد.


a6.gif

.
 

saeedsmk

مدیر بازنشسته
تاریخ عضویت
6 سپتامبر 2003
نوشته‌ها
1,518
لایک‌ها
4
اقا خيلي با حال بودن استفاده كردم .
مرسي
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
هدف من از پست قبل فقط اين بود كه بدانيد كه دستورات اسمبلي براي خود شخصيت دارند و اگر در قلب يك برنامه سي مي نويسيم به اين معني نيست كه جزيي از سينتكس سي هستند. با همين دستورات اسمبلي است كه خود توربو سي نوشته شده.

و كار با debug به نوعي يك تفريح بود در اينجا. و همان برنامه پست قبل را حالا من ((درون دل برنامه سي )) مي نويسم و زياد ديگه سمت برنامه debug نمي رويم و با استيل زير كار را ادامه مي دهيم.

کد:
#include <iostream.h>
#include <conio.h>


void main()
{
 clrscr();

[color=red]asm{
mov ah,2
mov dl,41h
int 21h

   }[/color]

getch();
}

برنامه بالا ، دقيقا همان كار را انجام مي دهد . يعني حرف A را چاپ مي كند. فقط بعد 41 يك حرف h من اضافه كردم. يعني هگزايي. بعد 2 هم ميشه اضافه كرد ولي 2 در دهدهي و هگزايي ، هر دو يكي است.

با يونيون و استيل سي هم ميشه نوشت و فرقي نمي كند. فقط در مبنا ها بايد دقت كرد.
حالا من كمي تعداد بايتها را شرح مي دهم.
اول به ax فكر كنيد. Ah و al داره. H و L مخفف كلمات high و low است. و بايت پايين و بايت بالاي ax مي گويند اينها را .
بايت كه مي دانيد 8 بيت است. هر 4 بيت 16 حالت مي تواند داشته باشد. كه از صفر تا f نام مي برند اين 16 حالت را . كه f همان 15 ميشه. پس a و b و c و d و e هم ميشه 10 تا 14 .
حالا اگر بخواهيم به قولي ax و ah و al را پر كنيم ميشه :

کد:
Ax=ffff
Ah=ff
Al=ff

البته ah و al اجزاي ax هستند و با پر كردن ax معلومه كه ah و al هم مقدار دهي شده اند.
حالا در ديباگ لازم نيست حرف h را بعد عدد بنويسيم . چون خودش به حالت پايه مبناي 16 در نظر ميگيره. ولي وقتي مثل برنامه بالا ،داريم در دل سي كدهاي اسمبلي را مي نويسيم ، به طور پايه مبناي 10 در نظر ميگيره و اگر مبناي 16 مورد نظر ماسا بايد حرف h را بعد عدد بگذاريم تا كامپايلر توربوسي بفهمه كه اينها اعدادي در مبناي 16 هستند.

وقتي هم كه داريد سورس اسمبلي مي سازيد تا با masm , tasm كامپايل كنيد، بايد به اين قضيه توجه كنيد . بايد ببينيد كه آنجا به طور پايه مبناي 10 در نظر ميگيره يا مبناي 16 . ولي فكر كنم برعكس محيط debug بود. يعني ميشد شبيه محيط توربو سي. يعني مبناي 10 . هر وقت طرز ساختن سورس و كامپايل با اسمبلر را گفتيم اين قضيه را بررسي مي كنيم. ولي فكر كنم اصلا نياز نباشه كه ما سورس اسمبلي بسازيم و با اسمبلر كامپايل كنيم. و همين جوري ((وسط برنامه سي)) بنويسيم خيلي راحت تره. چون محيط كارمون يكپارچه است و نيازي نيست يك اسمبلر هم با خود يدك بكشيم. .
ولي اگر كسي كارش اسمبلي خالص باشه ، مسلما با tasm و masm كار خواهد كرد نه با توربو سي.

= === ==== === === === == === ==
اما وقتي درون برنامه سي ، اين طوري دستورات اسمبلي را (بعد دستورasm) مي نويسيم ، محدوديتهايي داره و حدود 10 محدوديت ميشه كه من مقاله اي در اين مورد دارم. و فعلا لازم نيست بگم. مثلا يكي از آنها مثلا اين ميشه كه نمي توانيد زيربرنامه داشته باشيد و يا مثلا lable داشته باشيد . البته باز اين 2 مورد را با شك گفتم. بايد بعدا اين 10 مورد را نگاه كنم و شايد يك پست كردم و زدم.يا ادرس سايتش را اگر پيدا كردم مي دهم خودتان برويد بخوانيد. ما هم نمي خواهيم كه يك برنامه كامل اسمبلي بكاريم وسط سي كه! تا نياز به اينها داشته باشيم. پس ديگه با اين محدوديتها بحثي نداريم.

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

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
به نقل از saeedsmk :
شما كه استاديد
شرمنده مي كنيد.
===========================
براي ساختن سورس به روش زير مي شود اقدام كرد:

کد:
.model small

.stack
.code

[color=blue]test proc[/color]

mov ah,2h
mov dl,41h
int 21h

mov ah,4ch
int 21h

[color=blue]test endp[/color]

       [color=red] end test[/color]

در اديتور خود كدها را بنويسيد و با پسوند
asm
ذخيره كنيد. نت پد هم ميشه. كدوايز را هم در تاپيك اصلي براي دانلود گذاشته ام كه مخصوص سورس سازي براي زبانهاي مختلف نتي و سيستمي است. ولي فقط يك اديتوره.
بعد در محيط dos دستورات زير را براي كامپايل وارد كنيد:

کد:
tasm test.asm

link test

همان طور كه تابع اصلي داريم در سي ، اينجا هم داريم. دستوري كه قرمز نشان داده شده ، باعث بستن اين برنامه اصلي مي شود. و با قالب قسمت اصلي مي توانيم زير برنامه هم داشته باشيم كه با proc شروع و با endp تمام مي شود.

در موقعي كه برنامه لينك را بكار مي بريم يكسري سئوال مي پرسه كه ميشه با زدن اينتر از آنها گذشت.

در مورد خروج كه در debug با int 20 خروج مي كرديم ، در برنامه هاي exe بايد با سرويس 4c از int 21 خارج بشويم. در debug فايل com بود. و با debug نميشه فايل exe ساخت.
برنامه هايي براي تبديل اين دو بهم وجود دارد. يعني exe به com و بالعكس.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
حالا كه محيط debug را گفتيم و طرز سورس asm سازي و كامپايل با tasm را گفتيم ، ديگه ازش استفاده نمي كنيم و به محيط سي برمي گرديم.
اول همان برنامه چاپ A را در سي مي سازيم.

کد:
#include<conio.h>
#include<dos.h>

void main()						
{
clrscr();
         union REGS i,o;
		 i.h.ah=[color=red]0x[/color]2;
		 i.h.dl=[color=red]0x[/color]41;
		 int86([color=red]0x[/color]21,&i,&o);
       getch();
}

با قرار دادن 0x (صفر و ايكس) به كامپايلر مي گيم كه داريم مبناي 16 وارد مي كنيم.
به زبان ساده شرح برنامه بالا اين ميشه كه ah را 2 كرديم تا از سرويس شماره 2 وقفه 21 استفاده كنيم و بعد حرف A كه كدش 41 است را چاپ كرده ايم.

در برنامه بعدي، (پاييني) ، من قبل احضار وقفه و بعد احضارش ax و ah را چاپ كرده ام.

کد:
#include<conio.h>
#include<iostream.h>
#include<dos.h>


void main()						
{
clrscr();
	 union REGS i,o;
		 i.h.ah=0x2;
		  i.h.al=0x0;
		 i.h.dl=0x41;


cout<<endl<<"i.h.dl="<<i.h.dl<<endl;
cout<<"i.h.ah="<<i.h.ah<<endl;
cout<<"i.x.ax="<<i.x.ax<<endl;
			 int86(0x21,&i,&o);
cout<<endl<<"i.h.ah="<<i.h.ah<<endl;
cout<<"i.x.ax="<<i.x.ax<<endl;
			 getch();
}


a9.gif


در نتيجه اجرا ، يك حرف فارسي ((آ)) ديده ميشه كه وقتي فول اسكرين باشيم ، يك شكلك چاپ ميشه.
از نتيجه اجراي برنامه بالا نتيجه مي گيريم كه سي ، بايتها را كاراكتري چاپ مي كنه و دو بايت ها را عددي . در بكارگيري ماوس هم چون از dx و cx ، مكان قرار گيري ماوس را استخراج مي كرديم ، به شكل عددي برمي گرداند و استفاده ازش ساده بود.
ولي چرا ax شده 512 ؟ علتش اينه كه سي چون ax را تركيب al و ah مي دونه ، اين دو را با هم تركيبي گزارش مي دهد. يعني ah را در 256 ضرب مي كنه و با al جمع مي كنه و نتيجه را در ax قرار مي دهد.
من براي اينكه يادم بمونه اين طوري مي گم. 4 بيت مي تواند 16 حالت داشته باشه(حاصلرب 2 ، چهار بار ضرب در خودش ، و بايت كه 8 بيته ميشه 16*16 كه ميشه 256 .
پس ah ضرب در 256 ميشه و با al جمع ميشه.
حالا ما مي توانيم با اين محاسبات بفهميم كه مثلا الان al چند است. چون ax الان 512 است و وقتي بر 256 تقسيم كنيم ، هيچ باقي مانده اي ندارد ، پس براي al چيزي نمي مونه و حاصل تقسيم را هم ah در نظر مي گيريم.

در برنامه زير اين تقسيم كردن و محاسبه باقي مانده را به خود سي واگذار مي كنم و براي اينكه مطمئن بشم al را درست محاسبه مي كند، مقدار 7 بهش مي دهم. و مي بينم كه 7 هم چاپ ميشه.يعني محاسبات درسته.

کد:
#include<conio.h>
#include<iostream.h>
#include<dos.h>


void main()						
{
clrscr();
	 union REGS i,o;
		 i.h.ah=0x2;
		  i.h.al=0x7;
		 i.h.dl=0x41;


cout<<endl<<"i.h.dl="<<i.h.dl<<endl;
cout<<"i.h.ah="<<i.h.ah<<endl;
cout<<"i.x.ax="<<i.x.ax<<endl;
cout<<"    my_ah="<<i.x.ax/256<<endl;
cout<<"    my_al="<<i.x.ax%256<<endl;

			[color=red] int86(0x21,&i,&o);[/color]
cout<<endl<<"i.h.dl="<<i.h.dl<<endl;
cout<<"i.h.ah="<<i.h.ah<<endl;
cout<<"i.x.ax="<<i.x.ax<<endl;
cout<<"    my_ah="<<i.x.ax/256<<endl;
cout<<"    my_al="<<i.x.ax%256<<endl;
			 getch();
}


b1.gif


احضار وقفه همان خط قرمز است كه در نتيجه چاپ ، همان حرف A را چاپ كرده. بقيه نتايج اجرا cout هاي خودمان است.
.
================
ولي يادتان باشد كه عددي كه سي برمي گردانددر مبناي 10 است و عددي كه ما وارد كرديم در مبناي 16 وارد كرديم. من بجاي 7 آمدم 27 وارد كردم و 39 برگشت .
يعني 27 در مبناي 16 ، داخلش يك(( 2ضرب در 16 )) هست و يك 7 كه ميشه 39.
.
================
و مي توانيد اصلا به مبناي 10 بدهيد كه اين مشكلات پيش نياد.
يعني
0x
نگذاريد. ولي شماره سرويس ها را درست تبديل كنيد به مبناي 10
2 همان 2 ميشه در اينجا ولي سرويسهاي بالاي 9 ديگه اعدادشان در مبناي 10 و 16 بايد حساب بشه.
همين طور شماره وقفه ها را درست بايد بدهيد. اگر از شماره سرويس را درست ندهيد و وقفه اي را كار بياندازيد ممكنه قفل كنه كه با كنترل +
break
خارج بشيد.
.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
کد:
#include<conio.h>
#include<iostream.h>
#include<dos.h>

void main()						
{
clrscr();
	 union REGS i,o;
		 i.h.ah=0x2;
		 i.h.dl=0x41;
int86(0x21,&i,&o);  // chaap +++++++++++++++++++

cout<<endl<<"my_dl="<<i.x.dx%256<<endl; // +++++

asm{
mov ah,2

int 21h            // chaap ++++++++++++++++++++

mov dl,24h
   }

cout<<endl<<"my_dl="<<i.x.dx%256<<endl; // +++++

			 getch();
}

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

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

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

saeedsmk

مدیر بازنشسته
تاریخ عضویت
6 سپتامبر 2003
نوشته‌ها
1,518
لایک‌ها
4
سلام سالك جان
با اجازه شما
فكر كنم دنيال يه همچين چيزي بوديد نه ؟
کد:
#include<conio.h>
#include<string.h>

void main(){
char strDumm[10];
	clrscr();
	// set strDumm="saeed"
	strcpy(strDumm, "saeed");
	asm{
		// set zero al reg need
		xor ax,ax
		xor dx,dx
		xor bx,bx
		// set bx pointer to strDumm
		lea bx,strDumm
		// set function parameter (print char)
		mov ah,2h}
loopSec:
asm{
		// dl=what bx point to ( another function parameter)
		mov dl,[bx]
		// test if dl=0 : we reach to end of string
		// so we must break loop
		test dl,dl
		jz endSec
		// increase pointer value
		inc bx
		// call function
		int 21h
		jmp loopSec}
endSec:
	getch();
}
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
احسن.
عاليه.
شما آمديد رشته اي ايجاد كرديد و با ايجاد حلقه اي اين رشته را با اسمبلي چاپ كرده ايد.

و در ضمن يك مانور انجام داده ايد كه آن اين است كه از داخل قسمت اسمبلي به قسمت سي لينك داده ايد با ليبل. كه من در خواب هم اين كار به ذهنم نمي رسيد.

كلا برنامه خيلي قشنگه. دستتون درد نكنه. اجرا هم كردم . نتيجه اجرا saeed بود.
من بايد چند تا برنامه بنويسم و كارهاي مختلفي كه شما همه را در اين برنامه واحد انجام داده ايد را تمرين كنم.

ولي هنوز نكات زيادي در برنامه شما براي من رمزآلود است. شما در قسمت اول اسمبلي ah را تنظيم كرده ايم. (سرويس 2 ) ولي در قسمت دوم اسمبلي وقفه را بكار انداخته ايد.
چه مكانيسمي نهفته است در اين كار؟ آيا قسمتهاي مختلف اسمبلي براي خود save رجيستر دارند؟ يا ما دو سري رجيستر داريم؟ يكسري براي سي و يكسري براي اسمبلي. چنين چيزي هم بعيد است.
از دستور test در اسمبلي استفاده كرديد كه من تابحال تجربه استفاده ازش را نداشتم. ولي jz را زياد استفاده كرده ام. كه معنايش اينه كه وقتي فلاگ صفر ، تنظيم بود پرش كن.

دستور inc هم يك دستور يك بايتي است كه باعث يك واحد افزايش است.
دستور jmp كه مخفف jump است مثل دستور goto عمل مي كند.

وقتي يك عدد با خودش xor بشه ، صفر ميشه.
دستور lea خيلي برام جالبه و دوست دارم سريع يادش بگيرم، خواهشا توضيح بدهيد. .
دستور strcpy را قبلا در تاپيك اصلي باهاش كار كرديم. يك رشته را در رشته ديگر قرار مي دهد. براي توضيحات بيشتر به آن پست مراجعه كنيد.
= == == == == == == == === ==
تكليف شب خودم: من ثابت كردم كه تغيير رجيسترها از سي به اسمبلي و بالعكس منتقل نميشه ولي با نوشتن اين سورس توسط آقا سعيد گل ، من حالا بايد بروم ببينم بين دو تكه اسمبلي چه چيزهايي منتقل ميشه.

تكليف شب دوم: با lea كمي ور بروم و ببينيم چه كاربردهاي عملي داره.
= === === === == === = == = =
بايد برنامه آقا سعيد را بيشتر توضيح مي دادم تا همه طرز كارش را بوضوح بدانند ولي به بعد موكول مي كنم و در برنامه هاي ساده تري كه خواهيم ساخت اين دستورات را تمرين مي كنيم.

=== ==== ==== === === === =
آقا سعيد دستت درد نكنه ، خيلي قشنگ بود و گره قسمتهاي مهمي را باز مي كنه.
برنامه دوستمان را توضيح دادم ولي براي آموزش كامل بيشتر لازم بود بحث بشه(شايد تا 6 برابر). آقا سعيد منتظر بعدي ها هم هستيم.
.
 

saeedsmk

مدیر بازنشسته
تاریخ عضویت
6 سپتامبر 2003
نوشته‌ها
1,518
لایک‌ها
4
سلام سالك جان خوبي عزيز ؟

درمورد سئوال ها تا اونجايي كه علمم اجازه ميده جواب ها تو ميدم
پرسيده بودي : چه مكانيسمي نهفته است در اين كار؟

ببين عزيز هنگامي كه يك برنامه كامپايل ميشه توي سي ، بر عكس بيشتر زبان ها تعريف هاي اضافي و فانكشنهاي اضافي صدا زده نميشه به همين دليل اگه شما توي قسمت قبلي asm يه چيز رو تعريف كنيد و دوياره بلا فاصله دستورات asm بعدي را احضار كنيد ( ليبل ها در واقعه كار خاصي را انجام نميدهند) هيچ ريجستري تغيير نميكنه پس انگار توي يك دفعه اين كار را انجام داديد. توي Asm توي سي شما نميتوانيد از ليبل ها استفاده كنيد پس با اين روش اين مشكل حل ميشه
ببينيد كد برنامه ما پس از كامپايل به اسمبيلي ميشه :
کد:
   @1@74: //start main function
	call	far ptr _clrscr // call clrscr
	mov	ax,offset DGROUP:s@ 
	push	ax  // stor address of “saeed”
	lea	ax,word ptr [bp-10]
	push	ax // stor address of our array
	call	far ptr _strcpy
	pop	cx // correct stack pointer sp
	pop	cx // correct stack pointer sp
	xor	 ax,ax // our first asm code
	xor	 dx,dx
	xor	 bx,bx
	lea	 bx,[bp-10] // by this code bx is pointer to our array
	mov	 ah,2h
@1@218:
	mov	 dl,c[bx] //now our sec code start u see there is no code between tow 
			  //separated code	 
	test	 dl,dl
	je	short @1@362
	inc	 bx
	int	 21h
	jmp	short @1@218
@1@362:
	call	far ptr _getch // call getch
	mov	sp,bp // restore sp pointer 
	pop	bp // restore bp 
	ret	// end main function
حالا ما اگر كدي ببين اين دو حلقه بگذاريم مثلا همان دستور كپي استرينگ ديگر برنامه ما درست عمل نميكند چون ax تغيير مينماييد.
پس يكسري reg بيشتر نداريم و چيزي هم ذخيره نميشود.
- دستور test dl,dl برابر cmp dl,0 است
- اما دستور lea باعث بار گذاري ادرس متغيير دوم در متغيير اول ميشه
توي سي اشاره گر ها ادرس متغيير را حمل ميكردن درسته ؟. خوب ما با استفاده از دستور lea توي اسمبلي اشاره گر به حافظه مي سازيم يعني اين دستور
کد:
Lea bx,strDumm
معادله دستور زيره
کد:
char *s;
 char b[10];
 s=&b[0];
فكر كنم كد زير توضيج خوبي براي اين مطلب باشه

کد:
#include<conio.h>
#include<string.h>
#include<iostream.h>

void main(){
char strDumm[10];
char *strP;
	clrscr();
	// set strDumm="saeed"
	strcpy(strDumm, "saeed");
	asm{
		// set bx pointer to strDumm
		lea bx,strDumm
		// transport this address to our pointer
		mov strP,bx
	    }
	    // print our string;
	cout << strP;
	getch();
}
- خوب در مورد انتقال اطلاعات همونطور كه توضيح دادم بر اساس نوع برنامه نويسي تغييرات حاصل ميشه من كد پست قبلي رو بصورت زير تغيير دادم تا متوجه ببنيد چه مشكلي ايجاد ميشه

کد:
#include<conio.h>
#include<string.h>

void main(){
char strDumm[10];
	clrscr();
	// set strDumm="saeed"
	asm{
		// set zero al reg need
		xor ax,ax
		xor dx,dx
		xor bx,bx
		// set bx pointer to strDumm
		lea bx,strDumm
		// set function parameter (print char)
		mov ah,2h
		}
	strcpy(strDumm, "saeed");
loopSec:
asm{
		// dl=what bx point to ( another function parameter)
		mov dx,[bx]
		// test if dl=0 : we reach to end of string
		// so we must break loop
		test dl,dl
		jz endSec
		// increase pointer value
		inc bx
		// call function
		int 21h
		jmp loopSec}
endSec:
	getch();
}
خوب همونطور كه ميبنيد به احتمال زياد عبارتي چاپ نميشود يا عبارت درست چاپ نميشود چون مقدار ax تغيير نموده است
براي حل اين مشكل كد رو بصورت زير تغيير ميشه داد تا مشكل حل بشه .

کد:
void main(){
char strDumm[10];
	clrscr();

	asm{
		// set zero al reg need
		xor ax,ax
		xor dx,dx
		xor bx,bx
		// set bx pointer to strDumm
		lea bx,strDumm
		// set function parameter (print char)
		mov ah,2h
		// stor ax in stack
		push ax}
	// set strDumm="saeed"
	// by storing ax in memory we can call our function
	// and after return from it we can restore our ax
	strcpy(strDumm, "saeed");
		// restore ax from stack 
		asm pop ax;
loopSec:
asm{
		// dl=what bx point to ( another function parameter)
		mov dx,[bx]
		// test if dl=0 : we reach to end of string
		// so we must break loop
		test dl,dl
		jz endSec
		// increase pointer value
		inc bx
		// call function
		int 21h
		jmp loopSec}
endSec:
	getch();
}


اميدوارم كمك كنه :lol:
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
فهميدم قضيه از چه قراره كه منتقل مي شود بين دو قسمت اسمبلي.
كدهايي را كه نوشتيد را بايد كار كنم.
.
============
================
====================
==============================
=========================================

توضيحات كامل بود و بي نقص.
فهميدم كه با اجراي دستورات سي بين دو قسمت اسمبلي ، رجيسترها تغيير مي كنند و ميشه با push كردن قبل اجراي دستورات سي و pop كردن بعد اجراي دستورات سي ، آن رجيستر را حفظ كرد.
== == == == === === === ==
توضيح راجع به پشته: پشته قسمتي از Ram است و رجيسترها حافظه هايي داخل cpu .
اين جور كه معلومه دستورات سي مدام از رجيسترها استفاده مي كنند. و بايد هم اين طور باشه چون رجيسترها را ميشه gate (دروازه ) هاي cpu دانست. پس وقتي cpu به كار واداشته بشه ، دروازه ها هم محل عبور و مرور خواهند بود. من دقيقا نمي دانم كه توابع سي چه تغييراتي روي رجيسترها مي دهند. ولي در برنامه هاي بالا كه آقا سعيد نوشته بود ، توابع رشته اي مذكور ، رجسترها را تغيير داده اند.

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

راجع به پشته بايد مواظب باشيم كه چيزي را كه روند هاي خودكار برنامه در پشته قرار مي دهند را برنداريم. و يا وقتي اين روندها آمده اند چيزي را كه قبلا گذاشته بودند ، بردارند ، با چيزي كه ما گذاشته ايم مواجه نشوند. چون آنها فكر مي كنند كه آن امانتي خوشان است و متوجه نمي شوند كه ما انداخته ايم و برنامه دچار مشكلات جدي مي شود. مثلا در اسمبلي وقتي زير برنامه اي احضار ميشه ، آدرس برگشت در پشته گذاشته ميشه تا بعد اين كه زير برنامه تمام شد توسط آن آدرس به دستور بعدي بعد احضار برگرده . و مي دانيد كه اگر آن آدرس را ما برداشته باشيم با pop يا چيزي روي آن قرار داده باشيم با push چه اتفاقي مي افتد. بله ديگه زيربرنامه نمي تواند به برنامه اصلي برگردد و برنامه فلج مي شود. پس نوبت را رعايت كنيد و وقتي قسمت خودكار چيزي روي پشته گذاشته ، اولا آن را برنداريد و اگر برداشتيد بدانيد چه زماني صاحبش به سراغش ميايد كه سر جايش بگذاريد و چيزي روي پشته نگذاريد و اگر گذاشته ايد بايد بدانيد كه روندهاي خودكار چه زماني به پشته مراجعه مي كنند و قبل مراجعه آنها ، آن چيز را برداريد.
= == == === == == = == = = = = == = = == =
راجع به دستور lea خيلي جالب بود و بسيار كاربرد دارد. من بارها اين دستور را ديده بودم ولي نمي دانستم نقشش چيست و حالا فهميدم چه قدر به درد بخور است . مثل اشاره گر است و همان قدر كه اشاره گر كاربرد مي تواند داشته باشد ، اين دستور هم مي تواند كاربرد داشته باشد. ولي هنوز در بكارگيري اش تمرين نكرده ام.
=== == == = = == = = == = == = == = = ===
راجع به دستور test هم ممنون. من قبلا با cmp آشنا بودم.
شرح دستور cmp : اين دستور تفريقي است كه انجام نمي شود. پس چه فايده اي دارد؟
ببينيد عالم محاسبات اسمبلي رابطه تنگاتنگي با فلاگها دارد. فلاگها هم كنار رجيسترها ، حافظه هايي در cpu هستند ولي يك بيتي هستند.
بهترين اسمي كه من مي توانم به آنها بدهم ، ((نشانه )) است. همين طور كه مي دانيد يك بيت فقط دو حالت دارد. پس كسي كه به يك بيت نگاه مي كند ، يا ان را روشن مي بيند يا خاموش. مثل اينه كه برويد جايي و ببينيد دري باز است. در دو حالت دارد ، يا باز است و يا بسته. اين باز بودن در يعني كسي از در عبور كرده.
حالا فلاگها را چه چيزي تغيير مي دهد؟ پاسخ : هر محاسبه اي كه انجام شود ، مي تواند يك يا چند فلاگ را تغيير دهد . با باز كردن ديباگ و زدن حرف r همراه نمايش رجيسترها ، 8 فلاگ هم به نمايش در مي آيد. كه با دو حرف نشان داده شده اند.
مثلا nz . حالا فرض كنيد با دستور add دو عدد را جمع كنيم و ((ده بر يك)) داشته باشيم. اين ((ده بر يك)) باعث ميشه كه چند فلاگ تغيير كنند. پس اگر دو عدد را جمع كنيد و به فلاگها نگاه نكنيد نمي توانيد به جمع كردن خود اعتمادي داشته باشيد.

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

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
از استادم مطلبي را نقل مي كنم.
.
نام تاپيك:آموزش assembly
آدرس:
http://www.myimei.com/forum/showthread.php?tid=112&pid=4658#pid4658
=============


ثبات ها:
ثبات ها حافظه های 8 ، 16 ، 32 و 64 بيتی در داخل پردازنده هستند.
که سرعت بسار بالايي دارند و می توان از آنها در ساختارهايی که به شمارنده و محاسبات زيادی نياز دارند استفاده کرد
در اين بخش با ثباتهای 16 بيتی کار داريم.

ثباتهای عمومی:
AX-BX-CX-DX
که هر کدام از دو قسمت 8 بيتی کم ارزش ، و پر ارزش تشکيل شده اند.
مثلاً AL بخش کم ارزش و AH بخش پر ارزش AX می باشد
و برای DX نيز DL, DH
خانه ها را از 0 شماره گذاری می کنيم (بنابر اين هر ثبات 16 بيتی از 0 تا 15 شماره گذاری ميشه
از ثبات CX در شمارنده ها استفاده ميشه ( متغيير کنترلی اتمام حلقه ها هستند)
نتيجه ضرب و تقسيم اعداد بزرگ در DX قرار می گيره.
به ثبات BX هم ثبات پايه می گن وبه عنوان انديس ازش استفاده می کنن.
ثبات AX هم در محاسبات زياد مورد استفاده قرار می گيره.

ثباتهای سگمنت:
ES-SS-DS-CS
در اين ثباتها آدرس شروع سگمنت هايی که قبلاً گفتم ذخيره می شه.

براي سگمنت پشته SS يا satack segment .
براي سگمنت داده DS يا data segment .
براي سگمت كد CS يا code segment .
براي سگمنت اضافي ES يا extra segment .

ثباتهای انديس:
BP-SP-SI-DI

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

ثبات BP=base pointer شامل افست(سالك : افست ، آدرس دوم است. در بالا همان كوچه فرض كرديم و آدرس اول را خيابان فرض كرديم.)

ثبات SP=stack pointer حاوي آفست بالاي پشته است. بالاي پشته يعني آخرين ورودي.
پشته در زبان اسمبلي از بالا بسته است و رو به پايين پر ميشه. (از نظر آدرس)

ثبات SI=source index براي عمليات بر روي رشته ها است و آدرس رشته منبع را نگهداري مي كند.

ثبات DI=destination index براي عمليات بر روي رشته ها است و آدرس رشته مقصد را نگهداري مي كند.

==== == ==== == == ==

ثباتهای وضعيت و کنترلی:
IP-FLAG

ثبات IP آفست دستور بعدی اجرايی برنامه را دارد

ثبات فلگها
CF-PF-AF-ZF-SF-TF-IF-DF-OF
يک ثبات 16 بيتی که 9 بيت آن به طور مشخص نامگذاری شده و وضعيت پردازنده رو نشون ميده.


b3.gif


بيت (c (carry برای نشان دادن وجود رقم نقلی در محاسبات که آنرا CF می نامند
بيت (D (direction به معنی جهت می باشد و جهت پردازش روی رشته ها رو مشخص میکنه (از چپ به راست یا برعکس) و با DF نشون داده میشه
بيت (P (parity) اگر صفر باشه نشاندهنده اينه که تعداد شيفت ها زوج بوده وگرنه فرد بوده و با PF نشون داده ميشه
بيت (A (auxiliary carry رقم نقلی کمکی هست و در محاسبات 8 بيتی اگه رقم نقلی استفاده ميشه و با AF نمايش داده ميشه
بيت (Z(zero اگر در نتيجه محاسبات صفر ايجاد بشه اين بيت برابر يک ميشه و با ZF نشون داده ميشه
بيت (S (sign اگر نتيجه محاسبات منفی باشه اين بيت 1 ميشه و با SF نشون داده ميشه
بيت (T(trap اگر اين بيت برابر يک باشه اجرای برنامه به صورت دستور به دستور در مياد و با TF نشون داده ميشه
بيت (I(interrupt اگر اين بيت 1 باشه سيستم به وقفه ها پاسخ ميده وگرنه اونارو ناديده می گيره که با IF نشون داده ميشه
بيت (O(overflow اگه در محاسبات بيت پر ارزش سرريز بشه بيت O صفر ميشه , fh OF نشون داده ميشه.
.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
يك سئوال:
من كمي با توربوديباگر كار كرده ام.
فكر كنم كارش اينه كه برنامه ما را به كد اسمبلي تبديل مي كنه. مي خواهم باز نصبش كنم و كمي كار كنم.
حالا سئوالم اينه كه ايا ميشه هر چند دستور اسمبلي را يك دستور سي دانست و به تدريج با ماهر شدن با ديدن سورس اسمبلي ، فهميد سورس سي چي بوده. البته اين يك كار ايده آل است. براي انجام نمي گم. چون مي دانم دوستان خيلي اطلاعات در اين مورد دارند مي خواهم استفاده كنم.
.
 

saeedsmk

مدیر بازنشسته
تاریخ عضویت
6 سپتامبر 2003
نوشته‌ها
1,518
لایک‌ها
4
سلام سالك جان
در كل بايد بگم به اين راحتي نيست
ميشه براي چندين دستور توي سي توي اسمبلي با تجربه اين كاري رو شما گفتيد انجام داد. ولي چون ما 4 تا ثابت همكاره و 4 تا ثابت معين داريم و بي نهايت سل حافظه ( درسته تعدادشون محدود ه اما چون باز هم اين تعداد زياد است باز ميشه با تقريب گفت بي نهايت ) ميشه يك كد رو به چندين حالت نوشت و در بعضي از مواقع فهميدن كد ها خط به خط سخته چه برسه به كلي نگريستن . فكر كنم با مثال دقيق تر بشه صحبت كرد
شما تابعي داريد با دو تا ورودي و يك خروجي توي سي مينويسيد
a=funcx(c,d) //call function
اما با اسمبلي بصورت ساده ميشه (1)
کد:
mov ax,d
push ax
mov ax,c
push ax
mov ax, offset funcx
call ax
( بجاي ax ميتونيد از bxو ... هم استفاده كرد)
کد:
push d
push c 
call word ptr xxx
كه xxx ادرس تابع ما درونش هست
و ....
كه همانطور كه ميبيني خيلي راحت نيست و در بعضي از موارد شما c و d كه حاصل توابع ديگري هستند ( funcc و funcd ) رو به تابع ميفرستيد همين دستور توي سي ميشه
کد:
d=funcd();
c=funcc();
a=func(c,d) // callfuction
كه توي اسمبلي ميشه
کد:
call call word ptr ddd
push ax
call call word ptr ccc
push ax
call word ptr xxx
كه ddd ادرس تايع funcd و cccادرس تايع funccو xxx ادرس تايع funcx را در خود دارد كه ميبيني با حالت 1 خيلي متفاوت شده ولي دستورات سي اون تقريبا شبيه هم هستند ( اينجا هم شبيه اند اما توي يه برنامه چندين خطي و يا هزارن خطي كاري كه شما گفتيد خيلي راحت انجام پذير نيست )

اميدوارم كمك كنه
 
بالا