0

اصول برنامه نویسی در اسمبلی

 
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

اصول برنامه نویسی در اسمبلی

بسمه تعالی

آموزش های تصویری و متنی و کتاب و مقاله و ... درباره اسمبلی ویندوز زیاد هست اما در مورد لینوکس متاسفانه میتوان گفت هیچ آموزش جامعی به زبان فارسی وجود ندارد.
در این تاپیک آموزش های زبان اسمبلی برای لینوکس قرار میگیرد .
یه نکته هم بگم که این ها برگرفته از کتاب اصول طراحی و پیاده سازی سیستم عامل و Assembly For Linux هست.
That's enough for preface
================================================== ==============
فصل اول :مقدمه
در این فصل با یک سری مفاهیم و اصول اولیه آشنا خواهیم شد.
معماری وان نیومن
یکی از اولین کامپیوتر های الکترونیک کامپیوتر انیاک بود.در این کامپیوتر امکان برنامه نویسی و اجرای برنامه های گوناگون نبود . هر حساب جدید نیازمند این بود که فیش ها و کابل ها را جابجا میکردند .
اما امروزه هر کامپیوتری قابلیت استفاده از برنامه ها را دارد در واقع هر حساب و عملیات جدید مساوی است با یک برنامه جدید.
در واقع جایی که برنامه قرار دارد حافظه (Memory) و جایی که عملیات ها و حساب ها را انجام میدهد پردازنده (Processor) نام دارد.
برنامه ها معمولا به هنگام اجرا شکل یک لیست از دستورات را به خود میگیرند.
برای محاسبات و عملیات ها و اجرای دستور ها کامپیوتر ها از شیوه ای به نام شیوه وان نیومن یا چرخ اجرایی واکشی ( Fetch-Execute-Cycle ) استفاده میکنند .

همانطور که در تصویر بالا مشاهده میکنید این شیوه شامل سه مرحله میباشد.
مرحله اول :
پردازنده یک فرمان را از حافظه بر میدارد .
مرحله دو :
دستور را اجرا میکند.
مرحله سه :
دوباره به مرحله یک باز میگردد.
به کامپیوتر هایی که از این روش استفاده میکنند به کامپیوتر های وان نیومن معروفند.
وان نیومن یکی از بزرگترین ریاضیدانان و نظریه پردازان کامپیوتر بود.
( بسیاری از متخصصان کامپیوتر او را به خوبی یاد نمیکنند  زیرا میگویند او با این کار ذهن ما را قفل کرده و طرحی جز طرح او دیگر برایمان قابل تصور نیست و نمیتوانیم طرح دیگری را ارایه دهیم )
دو نمونه از کامپیوتر هایی که از این سیستم استفاده نمیکنند کامپیوتر های DNA و کامپیوتر های کوانتومی هستند.
(البته این کامپیوتر ها هنوز برای استفاده در فضای واقعی و کاربران خانگی اماده نیستند و تنها در ازمایشگاه ها و دانشگاه ها استفاده میشوند .)

Enough for this session .

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:51 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

پرتابل (*قابل حمل) بودن سیستم عامل Unix در واقع نتیجه بازنویسی این زبان در زبان C در سال ۱۹۷۳ است. زیرا زبان C برای پرتابل بودن ایجاد شده بود .
 
اولین نسخه مستقل C توسط ریچارد استالمن از Free Software Foundation ایجاد شد . نام آن , GNU ( که مخفف Gnu's Not Unix است ) آنرا از به همراه داشتن کپی رایت Unix معاف میکند .سیستم عامل لینوکس بسیار بسیار به زبان C و کامپایلر GCC وابسته است.
 
کامپایلر در واقع برنامه ای است که یک برنامه به زبان های سطح بالا را ( مثلا C ) به یک کد ماشینی یا Machine Code ترجمه میکند که بتواند در Memory قرار گیرد.
برنامه ای که قابلیت قرار گرفتن در مموری و اجرا توسط پردازنده را داشته باشد فایل اجرایی یا Executable File یا Executable میگویند .
 
کامپایلر GCC در چهار مرحله کار میکند برای مثال اگر بخواهیم برنامه Hello World زیر را کامپایل کنیم :
 
کد PHP:
#include <stdio.h>
 
int main()
{
  printf("Hello World \n");
  return 0;
}  
مرحله اول : پیش پردازش ( PreProcess ) در این مرحله فایل های مختلف که در برنامه فراخوانی شده اند به سورس اضافه میشوند ( مثلا #include های اول برنامه ) برای مثال یک برنامه که فقط روی صفحه چاپ کند Hello World در این مرحله تبدیل میشود به :
کد PHP:
http://paste.ubuntu.com/7683949/  
مرحله سوم : Assemble : در این مرحله کد های اسمبلی به Object File تبدیل میشوند . برای ادامه کار تا این مرحله از سوییچ -c استفاده کنید .
مرحله چهارم : لینک : در این مرحله Object فایل به فایل اجرایی متناسب با سیستم عامل شما تبدیل میشود و فایل اجرایی نهایی تحویل داده میشود.
 
اگر قبلا اسمبلی کار کرده باشید حتما متوجه شده اید که با گرامر Intel که معمولا کار میکنیم متفاوت است که در جلسه بعد کاملا راجع به آن توضیح خواهم داد.
 
پس ترتیب کامپایل یک سورس کد زبان C به شکل زیر شد : 
 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:52 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

گرامر و نوع اسمبلی که در فایل .s دیدید ( همونی که Gcc درستش کرد ) یک مقدار با چیزی که از اسمبلی تو ذهنمون هست و جاهای دیگه دیدیم و در کل اون اسمبلی که استفاده میکنیم فرق داشت . به این زبان زبان اسمبلی Edlinas میگویند.
 
این زبان در اصل همان زبان اسمبلی Intel است . و Object Code هاش در لینوکس x86 اجرا میشه.در کل Edlinas یک محیط جذاب هست برای کسانی که میخوان اسمبلی بنویسن که از یک ادیتور یک اسمبلر و یک سیمولاتور تشکیل شده .
 
اما Edlinas یک اسمبلر محیط داس هست اگر شما داس روی رایانه خودتون ندارید میتونید از Dosemu استفاده کنید .
 
Dosemu
همانطور که گفته شد Dosemu به شما اجازه میده که برنامه های داس رو در ماشین لینوکس خودتون اجرا کنید.
میتونید از آدرس : www.Dosemu.org دانلودش کنید.
 
نکته : اگر میخواید Edlinas رو از طریق Dosemu اجرا کنید یادتون باشه اگر محیط گرافیکیش رو میخواید ( نه فقط اسمبلر رو ) $_graphics رو در Dosemu.conf برابر با "1" قرار بدید .
 
Nasm 
 
یکی از قوی ترین اسمبلر ها که هم در داس و هم در لینوکس به خوبی اجرا میشه Nasm هست NetWide Assembler
دارای دستور های بسیار برای گرامر های مختلف و امکانات فراوان میتوانید از آخرین نسخه آنرا از ادرس زیر دانلود کنید : http://www.nasm.us/pub/nasm/releasebuilds/
برای آنپک و نصب Nasm از دستورات زیر استفاده کنید :
کد PHP:
$unzip -aL nasm.zip 
سپس به یک دایرکتوری مناسب آنرا انتقال داده و برای build دستور زیر را وارد کنید : 
$cp makefile.unx Makefile 
$make  
اسمبلر هایی مثل Masm و Turbo Assembler هم استفاده گسترده ای دارند هرچند به خاطر سختی نوشتن اسمبلی در ویندوز محبوبیت خود را از دست داده اند .
 
منابع : 
 
Voice from OpenSource Revolution 
A Quarter Century of Unix

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:52 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

بیشتر کامپیوتر ها تنها یک برنامه در آن واحد را اجرا نمیکنند بلکه برنامه ای به نام سیستم عامل*(Operation System) را اجرا میکنند.سیستم عامل یک رابط کاربری برای کاربران ایجاد کرده و همچنین یک رابط کاربری راحت برای ارتباط با سخت افزار مانند CD_Driver , Printer , CPU ,.... ایجاد میکنند و باقی برنامه ها را اجرا میکنند.
اولین سیستم عامل توسط فروشندگان رایانه ایجاد شده بود. پس هر رایانه سیستم عامل مخصوص خود را داشت.اولین سیستم عامل مستقل سیستم عامل یونیکس ( UNIX ) بود که توسط گروهی از محققان در آزمایشگاه های( Bell (Bell Labs طراحی و توسعه داده شده بود.
 
 
AT&T , مالک اصلی Bell Labs , خیلی زود Unix را با قیمت کم روانه ی موسسات آموزشی و دانشگاه ها کرد و همین باعث گسترش بیشتر Unix شد.
 
ورژنی از Unix که در دانشگاه کالیفرنیا توسعه داده شد و دارای ویژگی های بسیار زیادی مانند پورتابل بودن ( قابلیت انتقال اسان بر روی انواع مختلف رایانه )* بسیار محبوب و مورد استفاده شد , به نام BSD یا (Berkeley Software Division ) شناخته شد.
 
لینوکس یک ورژن غیر اختصاصی از Unix است که توسط Linus Torvalds طراحی شده و توسط یک گروه بزرگ کاربران به صورت آنلاین توسعه داده شد.
 
امروزه بیشتر انواع لینوکس سازگار با Intel هستند و بیشتر کاربران لینوکس ( از جمله خود من  ) آنرا به صورت نصب شده در کنار سیستم عامل دیگر ( مثلا ویندوز ) دارند و داشتن پارتیشن های مختلف برای لینوکس و ویندوز یک چیز کاملا معمول و متداول است.

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:52 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

میخواستم وارد اسمبلی بشم اما یادم اومد که یک سری مقدمات رو نگفتم 
 
--------------------------------------
 
ببینید دوستان یه برنامه اسمبلی در واقع از سه تا بخش تشکیل میشه ( سه تا سگمنت ) که اون قسمت ها قسمت Data , Bss , Text هستن
 
قسمت Data برای نگهداری متغیر هایی هست که مقدار دهی اولیه میشن مثلا میگیم hello: db "Hello" اینجا ما الان متغیر Hello رو از نوع رشته ای و کاراکتر اسکی با مقدار اولیه Hello تعریف کردیم این کار رو در قسمت Data میکنیم.
 
ولی حالا میایم یه متغیر تعریف میکنیم ولی مقدار بهش نمیدیم اینو میزاریم توی قسمت BSS
 
و کد هامون رو هم ( همون ساختار چهارتیکه ای ) در قسمت Text مینویسیم .
 
ولی حالا ما اون متغیر ها رو در حافظه ذخیره کردیم دیگه ولی حافظه فقط متغیر ها رو ذخیره میکنه دیگه حالا مثلا اگر عدد 4 رو خواستیم استفاده کنیم مثلا به عنوان یک سیستم کال ( سیستم کال ها رو توضیح میدم  ) باید ذخیره کنیم تو متغیر بعد از تو اون استفاده کنیم ؟ چه کاریه ؟ 
 
برای این کار سی پی یو خودش یه حافظه هایی رو داره به نام رجیستر که به فارسی میشه ثبّات . ( خیلی ها به اشتباه میگن ثُبات اون غلطه ثبّات درست هست ثبت کننده  ) 
 
بعد حالا رسیدیم به مبحث شیرین رجیستر .
 
خیلی جا ها راجع به رجیستر ها توضیح دادن ولی حالا ما اینجا توضیح ها رو کوتاه میکنیم ببینید چند گروه رجیستر داریم :
رجیستر های عمومی :
EAX,EBX,ECX,EDX ( این ها مال Intel x86 هست ممکنه در بقیه سی پی یو ها یه جور دیگه باشه مثلا شونزده بیتی باشه این E اول اونها به معنی 32 بیتی بودنشون هست )
ثبّات های پشته : ESP,EBP ( راجع به پشته بعدا توضیح میدیم فعلا لازم نیست )
ثبّات های شاخص : ESI,EDI
ثبّات اشاره گر دستورالعمل : EIP
 
خوب حالا وقتی که بخوایم یه کاری انجام بدیم یا از یه تابعی استفاده کنیم مثلا فقط Close کنیم برنامه رو از چیز هایی استفاده میکنیم به نام سیستم کال ( میتونید لیست کاملی از سیستم کال ها رو در مسیر
کد PHP:
 /usr/include/asm/unistd.h  
و یا در آدرس : 
کد PHP:
http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html  
مشاهده کنید )
خوب برای اینکه یک عمل انجام بشه باید سیستم کالش در eax و آرگومان هاش ( اون چیزایی که اضافی بهش میدیم که روشون کار انجام بده )به ترتیب آرگومان اول در ebx دوم در ecx و سوم در edx قرار میگیرند.
 
خوب برای این قسمت دیگه کافیه
موفق و پیروز باشید

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:53 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

دستور IN دستور ورودی هست ( input ) که داده رو از پورت ورودی/خروجی میگیره و اون رو به پردازنده انتقال میده. به شش شکل زیر میشه این دستور رو استفاده کرد .
 
کد PHP:
IN EAX, [DX] 
IN AX, [DX] 
IN AL, [DX] 
IN EAX, [imm] 
IN AX, [imm] 
IN AL, [imm]  
(imm هر عدد تک بایتی هست )
نکته : شکل کلی هر دستور به شکل زیر هست : 
کد PHP:
COMMAND destination,source  
(اگر انگلیسیتون خوب نیست source یعنی منبع ، destination یعنی مقصد )
مثلا همین اینجا مقصد ما یا EAX یا AX یا AL هست و از اون طرف هم منبع ( جایی که میخوایم ازش چیزی برداریم ) یا DX هست یا خود عدد ( همون imm ) مثلا فرض کنید میخوایم از یک دستگاه ورودی یه چیزی بگیریم حالا شماره پورت اون دستگاهه میتونه توی DX ذخیره شده باشه یا مستقیم به صورت عدد بریزیمش توی منبعمون .
توجه کنید که DX یک رجیستر 16 بیتی هست این به خاطر این هست که یک شماره پورت ( پورت دستگاه ورودی/خروجی) یک عدد 16 بیتی هست .
یک نکته هم توجه کنید که [DX] به داده ای که در DX قرار گرفته اشاره میکنه .
دستور OUT :
 
دستور خروجی OUT داده رو از پردازنده به دستگاه خروجی منتقل میکنه شش شکل استفاده out هم این شکل های زیر هست :
کد PHP:
OUT [DX],EAX 
OUT [DX],AX 
OUT [DX],AL 
OUT [imm],EAX 
OUT [imm],AX 
OUT [imm],AL  
اینجا میایم یک داده رو از رجیستر یا به صورت عدد به یکی از دستگاه های خروجی میده .

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:53 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

در زبان های سطح بالا یک برنامه ساده اول یه ورودی میگیره یه کاری روش انجام میده و بعد چاپش میکنه در اسمبلی هم ما میخوایم همین کار رو بکنیم .
 
 
نکته :* فعلا ما با Edlinas برنامه مینویسیم پس برای چاپ در صفحه نمایش و دریافت مقدار از کیبورد از پورت های Edlinas استفاده میکنیم ( پس این برنامه ها در داس و یونیکس کار نمیکنن فقط در لینوکس کار میکنن )* بعدا میبینید که چطور با استفاده از سیستم کال ها توابع Printf() و scanf() رو شبیه سازی میکنیم .
 
 
ما برای استفاده از ورودی و خروجی در Edlinas از دو پورت استفاده میکنیم :
 
− پورت 0 برای ورودی کیبورد 
− پورت ۱ برای خروجی نمایشگر
 
ورودی کیبورد در پایین سمت چپ صفحه نمایش داده میشه و خروجی در پایین سمت راست صفحه .
خوب پس الان اون دستورای پست قبلی باید براتون واضح تر شده باشه یعنی اینکه الان وقتی میزنیم :
کد PHP:
IN EAX,[DX]  
مقداری که توی DX هست باید صفر باشه تا از کاربر یک ورودی بگیره و همچنین در دستور :
کد PHP:
OUT [DX],EAX  
مقدار DX باید ۱ باشه تا مقدار خروجی در مبنای ده روی خروجی استاندارد نمایشگر نمایش داده بشه .
 
همین ورودی و خروجی به شما کمک میکنه تا برنامه های خیلی ساده ای در Edlinas بنویسید . البته همونطور که گفتم این برنامه هایی که از پورت های Edlinas استفاده میکنن بهتره توی لینوکس اجراشون کنید .
--------------------

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:53 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

دستور RET
 
هر برنامه (*هر پروسه )* توسط سیستم عامل داره اجرا میشه حالا آخر برنامه کار که تموم شد یک مقدار رو به سیستم عامل برگردونه که سیستم عامل بفهمه برنامه به خوبی اجرا شده و بره سراغ کار های بعدی هر زیر برنامه هم ( مثل توابع ) باید یک مقدار رو به خود برنامه برگردونه (*مثلا یه تابع درست میکنیم که یه مقدار رو بگیره ده برابر کنه اون ده برابره مقدار بازگشتی از تابع هست )* برای برگردوندن مقدار بازگشتی از دستور RET استفاده میکنیم که در آینده راجع بهش بیشتر صحبت میکنیم .
 
 
اولین برنامه ساده :
ما اینجا میخوایم یه برنامه بنویسیم که دو عدد رو از ورودی بخونه حاصل جمعشون رو بهمون بده .
 
اینجا یک برنامه Edlinas خیلی ساده هست که این کار رو برامون انجام میده :
( یادداشت ها رو مجبور شدم فینگیلیش بزارم چون تو کد فارسی به هم میریزه )
کد PHP:
Mov EDX , 0 ; meghdare edx ke 32 bit hast ro sefr mikone pas DX ham ke 16 bit azash hast sefr mishe 
IN EAX,[DX] ; avalin adad ro ba porte sefr az karbar mikhone 
MOV EBX,EAX ; adade aval ro mirize toye ebx 
IN EAX,[DX] ; dovomin adad ro ham migire 
ADD EAX,EBX ; meghdari ke to ebx hast ke dar vaghe adade avalemon hast ro ba adade dovom ke dar eax hast jam 
MOV EDX,1 ; yek ke porte khoroji hast ro mirize toye dx 
OUT EAX,[DX] ; meghdari ke toye eax hast ke hasele jam hast ro ba porte yek ke porte khoroji hast chap mikone  
RET ; be system amel mige ke barname tamom shod  
برنامه رو یک بار بدون یادداشت مینویسم تا مشکلی در خوندنش نباشه :
کد PHP:
MOV EDX,0 
IN EAX,[DX] 
MOV EBX,EAX 
IN EAX,[DX] 
ADD EAX,EBX 
MOV EDX,1 
OUT EAX,[DX] 
RET  
دیدید که خیلی ساده اومد اول یه عدد گرفتم و بعد ریخت توی ebx بعد اومد یه عدد دیگه گرفت و حالا مقداری که توی ebx بود رو باهاش جمع کرد و بعد هم چاپش کرد.
 
 
پرش ها در اسمبلی
 
اگر با زبون دیگه ای مثل سی کار کرده باشید (* که حتما کردید ) میدونید که چیزایی تو زبونای سطح بالا وجود دارن به نام حلقه ( مثل While ) که کارشون این هست که مادامی که یک شرط درست هست یک سری دستور رو انجام میدن و وقتی شرط نادرست شد کار رو به پایان میرسونن خوب حالا فکر کنید این حلقه ها تو اسمبلی چه طور میشن ؟؟؟ ما که تو اسمبلی چیزی به نام حلقه نداریم که پس اینا چه جوری توسط کامپایلر به زبون اسمبلی ترجمه میشن ؟
 
توسط شرط ها و پرش ها
فلوچارت یک حلقه while اینجوری میشه :
 
 
 
خوب پس نیاز به پرش ها رو فهمیدیم .
 
برای اینکه if else ها و حلقه ها در زبان های سطح بالا به اسمبلی ترجمه بشن از پرش استفاده میکنیم با استفاده از لیبل ها که در چند پست قبل گفتیم میگه اگه فلان شرط درست بود بپر به این لیبل اگه درست نبود بپر به اون یکی لیبل .
چون سیستم کامپیوتر اینجوریه که هر دستوری که داره اجرا میشه آدرس دستور بعدیش توی eip ( instruction pointer ( ذخیره میشه و بعدش میره سراغ اون آدرس ولی با پرش آدرس اون لیبل توی eip ذخیره میشه .
 
ما برای پرش از دستور jmp استفاده میکنیم و کاربردش هم به صورت زیر هست*:
کد PHP:
jmp label  

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:53 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

خوب ما الان میخوایم یه برنامه بنویسیم که دو مقدار رو از کاربر بگیره مقدار اول رو در ebx و مقدار دومی رو eax ذخیره کنه اگه اولی بزرگتر بود عدد ۱ رو برگردونه اگر دومی بزرگتر بود عدد ۲ رو برگردونه برای مقایسه چیکار کنیم ؟
با توجه به این چیزایی که تا حالا یاد گرفتیم میخوایم یه مقایسه انجام بدیم میتونیم اولی رو از دومی کم کنیم و بعد با توجه به این پرچم ها که یاد گرفتیم میایم و میگیم اگر حاصل منفی بود پس دومی بزرگتره اگه منفی نبود اولی بزرگتره خوب پس بیاید برنامه اش رو بنویسیم :
کد PHP:
MOV EDX,0
IN EAX,[DX]
MOV EBX,EAX
IN EAX,[DX]
SUB EBX,EAX
JS SIB
MOV EAX,1
JMP END
SIB:    MOV EAX,2
END:    MOV EDX,1
OUT [DX],EAX
RET  
خوب حالا خط به خط برنامه رو تحلیل میکنیم
خط اول که edx رو صفر میکنه که dx هم صفر بشه برای ورودی گرفتن
خط دوم هم که یه ورودی میگیره که عدد اولی هست که کاربر وارد میکنه
تو خط سوم میایم و اون عدد رو میریزیم توی ebx که عدد دوم رو بتونیم بگیریم
تو خط چهارم عدد دوم رو از کاربر میگیریم و میریزیمش توی eax
تو خط پنجم عدد اول رو منهای دومی میکنیم یعنی :
avali - dovomi
بعد حالا تو خط ششم یک پرش شرطی میکنیم که در صورتی که sign flag ست شده باشه میپره sign هم که توضیح دادیم در صورتی ست میشه که حاصل تفریق منفی باشه خوب حالا اگر منفی باشه که یعنی دومی بزرگتر بوده میپره به SIB که یعنی Second is bigger دومی بزرگتر است که توش میزاریم eax رو برابر با ۲ قرار بده اگر حاصل منفی نباشه eax رو برابر با ۱ قرار میده و میپره به end اگر هم دومی بزرگتر باشه که باز هم بعد از SIB میره به end در end میگیم که edx رو برابر با ۱ قرار بده و بعد هم با استفاده از پورت خروجی که همین 1 هست عدد توی eax رو چاپ کنه که معلوم بشه کدوم بزرگتر بوده آخرش هم که با ret* برنامه رو تموم میکنیم .
این یک برنامه بسیار ساده بود برای مقایسه دو عدد اما این برنامه هنوز باگ داره تا پست بعد عدد های مختلف رو امتحان کنید ( مثلا مقایسه عدد مثبت و منفی )

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:54 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

میدونید که ما توی اسمبلی عملگری به نام ضرب نداریم باید با استفاده از حلقه به تعداد عدد اول دومی رو با خودش جمع کنیم ولی خوب چیزی به نام حلقه ملقه هم نداریم :d چیکار میکنیم ؟
میایم با استفاده از همون پرش ها و پرش های شرطی یه حلقه برا خودمون درست میکنیم کامپایلر ها هم با همین روش حلقه ها و ضرب ها رو به زبون اسمبلی میبرن .
ما الان میخوایم مثلا ضرب 7*5 رو انجام بدیم پس کاری که در واقع باید انجام بدیم این هست ۵+۵+۵+۵+۵+۵+۵ :
پس ما میایم اول یه عدد از کاربر میگیریم که کاربر ۷ رو وارد میکنه بعد یه عدد دیگه میگیریم که ۵ رو وارد میکنه بعد میایم میگیم هر بار یکی از هفت کم کن اگر هنوز صفر نشده دوباره بپر به اول و پنج رو به حاصل قبلی اضافه کن واضحه برنامه به این شکل میشه :
کد PHP:
mov edx,0 
in eax,[dx] 
mov ebx,eax 
in eax,[dx] 
mov ecx,0 
rpt :   Add ecx,eax 
sub ebx,1 
jnz rpt 
mov eax,ecx 
add edx,1 
out [dx],eax 
ret  
این برنامه خیلی ساده دو تا عدد میگیره و حاصل ضربشون رو نمایش میده 
در خط اول که اومدیم edx رو صفر کردیم برای اینکه با کمک [dx] بتونیم ورودی بگیریم
تو خط بعد عدد اول رو میگیریم و میریزیمش توی eax
تو خط بعد عدد اول رو میریزیم توی ebx 
تو خط بعد عدد دوم رو از ورودی میگیره
بعد ما میخوایم از ecx به عنوان حاصل جمع استفاده کنیم پس برای همین مقدار اولیه اش رو صفر میکنیم .
تو خط بعد با لیبل rpt میایم میگیم که عدد دوم رو با حاصل جمع که الان صفر هست جمع کنه
تو خط بعد از عدد اول یکی کم میکنیم 
و تو خط بعدش میگیم که اگه عدد اول هنوز صفر نشده دوباره بپر به همون ضربمون
بعدش هم که دیگه حاصل جمع رو میریزیم توی eax و edx رو یک میکنیم و حاصل جمع رو نمایش میدیم
این یک برنامه خیلی ساده ضرب با استفاده از حلقه بود پس یاد گرفتیم که چطور یه حلقه با یه شرط درست کنیم ولی این برنامه هم باگ همون برنامه قبلیمون رو هنوز داره ....

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:54 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

دستورات INC و DEC :
در اسمبلی دو دستور داریم به نام های INC که یعنی افزایش و DEC یعنی کاهش .
معادل دستورات ++ و -- در زبان سی .
 
دستور INC یک مقدار به مقدار ما اضافه میکند و DEC یکی کم میکند این دستورات رو با یک رجیستر استفاده میکنیم .
به این صورت 
کد PHP:
INC eax 
DEC eax  
به جای eax میشه بقیه رجیستر ها رو هم قرار داد .
این دو دستور معمولا در حلقه ها به کار میروند .
مثلا در مثال قبل درستش اینه که بیایم و به جای 
کد PHP:
SUB EBX,1 
از  
DEC EBX  
و به جای
کد PHP:
ADD EDX,1 
از 
INC EDX  
استفاده کنیم .
 
مقایسات علامت دار 
 
پرش های بر پایه مقایسه ( Comparison Based Jumps ) 
اگر با برنامه نویسی آشنا باشید ( باید باشید  ) میدونید که در زبان های برنامه نویسی اکثرا از گزاره های شرطی If .. Then .. Else و یا Switch استفاده میکنیم از اونجا که تو دنیای صفر و یک از این تنبل بازی ها نداریم پس میایم و از مقایسه ها استفاده میکنیم .
چطور ؟
مثلا چطور میشه تشخیص داد که B کوچک تر از A هست ؟؟ اگر B-A منفی باشه 
از اونجایی که قبلا توضیح دادیم یک flag داریم به نام Sign Flag که علامت رو مشخص میکنه ( اگر منفی باشه ست هست اگر نباشه clear هست ) به نظر میاد کارمون خیلی راحت باشه اما اونقدرا هم راحت نیست  .

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:54 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

دستور CMP 
دستور cmp که در واقع یعنی مقایسه ( compare ) دقیقا کار sub رو انجام میده با این تفاوت که مقدار destination رو تغییر نمیده یعنی تفریق رو انجام میده و تمام flag ها رو دقیقا مثل sub تغییر میده اما فرقش اینه که حاصل تفریق رو دیگه به ما نمیده فقط برای مقایسه به کار میره خیلی به صرفه تره اگر به جای sub از cmp استفاده کنیم چون انرژی کم تر و زمان کمتر میگیره .
 
اگر یادتون باشه برنامه ای نوشته بودیم که دو تا عدد رو میگرفت و میگفت که کدومش بزرگ تره حالا میخوایم همون برنامه رو به صورت بهینه تر و با دستورات بهتر مجددا بنویسیم :
 
خوب اول که باید عدد اول رو بگیریم بریزیم تو ebx و دوم رو بریزیم تو eax که بدونیم کی به کیه 
کد PHP:
mov edx,0
in eax,[dx]
mov ebx,eax
in eax,[dx]  
خوب حالا میایم برنامه ای که نوشته بودیم رو این بار با استفاده از CMP و JL مینویسیم :
کد PHP:
CMP ebx,eax
JL SIB
mov eax,1
JMP END
SIB:    mov eax,2
END:    mov edx,1
out [dx],eax
ret  
این برنامه برای تمام اعداد چهار بایتی ( :O ) کار میکنه ( البته به شرطی که عدد های ما علامت دار نباشن در واقع مثبت باشن )

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:54 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

دستور CMP 
دستور cmp که در واقع یعنی مقایسه ( compare ) دقیقا کار sub رو انجام میده با این تفاوت که مقدار destination رو تغییر نمیده یعنی تفریق رو انجام میده و تمام flag ها رو دقیقا مثل sub تغییر میده اما فرقش اینه که حاصل تفریق رو دیگه به ما نمیده فقط برای مقایسه به کار میره خیلی به صرفه تره اگر به جای sub از cmp استفاده کنیم چون انرژی کم تر و زمان کمتر میگیره .
 
اگر یادتون باشه برنامه ای نوشته بودیم که دو تا عدد رو میگرفت و میگفت که کدومش بزرگ تره حالا میخوایم همون برنامه رو به صورت بهینه تر و با دستورات بهتر مجددا بنویسیم :
 
خوب اول که باید عدد اول رو بگیریم بریزیم تو ebx و دوم رو بریزیم تو eax که بدونیم کی به کیه 
کد PHP:
mov edx,0 
in eax,[dx] 
mov ebx,eax 
in eax,[dx]  
خوب حالا میایم برنامه ای که نوشته بودیم رو این بار با استفاده از CMP و JL مینویسیم :
کد PHP:
CMP ebx,eax 
JL SIB 
mov eax,1 
JMP END 
SIB:    mov eax,2 
END:    mov edx,1 
out [dx],eax 
ret  
این برنامه برای تمام اعداد چهار بایتی ( :O ) کار میکنه ( البته به شرطی که عدد های ما علامت دار نباشن در واقع مثبت باشن )

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:54 AM
تشکرات از این پست
siryahya
siryahya
کاربر طلایی1
تاریخ عضویت : اسفند 1389 
تعداد پست ها : 158507
محل سکونت : ▂▃▄▅▆▇█Tabriz█▇▆▅▄▃▂

پاسخ به:اصول برنامه نویسی در اسمبلی

دیدیم که بعد از cmp eax,ebx زمانی که jl بیاد تفریق انجام میشه فلگ ها تغیر میکنن و jl بر حسب فلگ ها پرش رو انجام میده اما فقط همین یه دستور نیست دستورات دیگه ای هم هستن که یه cmp رو دنبال میکنن :
JL یعنی Jump if Less than یعنی اگر کوچیک تر بود 
JLE بپر اگر کوچیک تر یا مساوی بود
JG بپر اگر بزرگتر بود 
JGE بپر اگر بزرگتر یا مساوی بود
JE بپر اگر مساوی بود
JNL بپر اگر کوچک تر نیست
JNLE بپر اگر کوچک تر یا مساوی نیست 
JNG اگر بزرگتر نیست
JNGE اگر بزرگتر یا مساوی نیست 
JNE گر مساوی نیست
میبینید که مقایسه و پرش های مقایسه ای بسیار بسیار آسون هستن حتی آسون تر از if else های توی سی .

 

ترکی زبان قربون صدقه رفتنه داریم که: گوزلرین گیله‌سین قاداسین آلیم که یعنی درد و بلای مردمک چشات به جونم …!.

دوشنبه 21 اردیبهشت 1394  2:55 AM
تشکرات از این پست
دسترسی سریع به انجمن ها