آموزش اسمبلی، گام اول

سلام
اگه یادتون باشه، آخرین بار با مطلبی به نام «پروژه ساده با اسمبلی؛ برنامه جمع دو عدد» سعی کردیم کمی شما رو با کلیت زبان برنامه‌نویسی اسمبلی آشنا کنیم.
یعنی صرفا برای بدست آوردن یه دید کلی بود.
البته اون‌طور که متوجه شدم، برای برخی مخاطبین که با زبان‌های سطح پایین و کلا اسمبلی آشنا نبودن، خیلی گنگ بود!
واقعیت اینه که مشکل خیلی از من نیست؛ چون پیش‌نیاز درک اسمبلی، شناخت مختصری از معماری کامپیوتر و عملکرد پردازنده هست.
این بار قراره وارد جزئیات بشیم؛ اما بازم پیش‌نیاز درک مفاهیم پردازنده وجود داره.
چون اصلا دلم نمیخواد مثلا توضیح بدم رجسیتر چیه، ساختار حافظه رم چطوریه و… 🙃
اما انتظار میره که با این مفاهیم آشنا باشید.
با من همراه باشید.

مفهوم اسمبلی

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

توی اسمبلی، ما مستقیما با پردازنده مرتبط می‌شیم و بهش دستور می‌دیم! و همین‌طور دستورات ما به شکل مستقیم روی رجسیترهای(ثبات‌های) پردازنده و حافظه تاثیر می‌گزاره.

برنامه تحت اسمبلی

یه برنامه و در واقع کد کامل اسمبلی معمولا از دو بخش اصلی تشکیل میشه:
.data : بخش مربوط به داده‌ها (متغیرها،رشته‌ها و…)
.text : بخش کد و دستورات
و یه نقطه شروع همیشه برای برناممون داریم که کدها از اونجا شروع به اجرا شدن می‌کنن.
_start

(پیشنهاد می‌کنم هم‌زمان مطلب قبل رو باز کنید و سعی کنید نگاهی به کد داشته باشید)

برخی دستورات:

MOV

اگه به سورسی که توی مطلب سابق هست نگاهی بندازید، می‌بینید که از دستور MOV زیاد استفاده شده.
همون‌طور که از اسمش مشخص هست، برای جابجایی هست.
مثلا در

عدد 3 در رجسیتر eax قرار گرفته.
همین‌طور اگه توی سورس نگاه کنید، ما بعد از گرفتن مقدار num1 ، اون رو در ecx ریختیم.

ADD

مشخصا برای جمع استفاده می‌شه.
مثل:

مقادیر درون رجیستر‌های eax و ebx با هم جمع شدن.
اما اگه دقیق‌تر بگیم، ebx اضافه شده به eax.

SUB

این هم مخفف subtract هست و برای تفریق استفاده می‌شه.
مثل:

 

تو این دستور، مقدار موجود در رجیستر ebx از eax کم می‌شه.
یعنی خروجی نهایی داخل eax قرار می‌گیره و ebx هم بدون تغییر می‌مونه.

(نکته: رجیسترها مثل متغیر نیستن که با = مقدارشون عوض بشه؛ بیشتر مثل ظرف‌هایی هستن که عملیات مستقیم روشون انجام می‌گیره.)

INT

برای ایجاد وقفه (Interupt) استفاده می‌شه؛ مثلا:

اینجا درخواست می‌کنیم یه «خدمت» یا همون syscall برامون انجام بده.
این خدمت می‌تونه خروج از برنامه باشه (exit)، چاپ چیزی روی صفحه (write) یا حتی خوندن از ورودی.
ولی یادتون نره که قبلش باید توی رجیستر eax شماره syscall مربوطه رو بذارید، و رجیسترهای دیگه رو هم بر اساس نوع درخواست پر کنید.
(الان باید مطلب قبل رو بهتر متوجه بشید)

مثلاً برای خروج از برنامه:

 

 

محاسبه طول رشته

توی این خط کد داریم یه ثابت به نام len_resultMsg تعریف می‌کنیم که مقدارش برابر باشه با تعداد بایت‌های بین resultMsg و $، یعنی طول رشته‌ای که با resultMsg شروع شده.

 

توی این مطلب سعی کردم یه مرور جزئی‌تر از برخی دستورات پایه اسمبلی داشته باشم.
تو قسمت بعدی احتمالاً بریم سراغ مفاهیم مهم‌تری مثل استک (stack)، فراخوانی تابع، و مدیریت حافظه توی اسمبلی.
اگه الان که اینجا هستید، حس کردید یه چیزی گنگه یا جا نیفتاده، کامنت بذارید اینجا یا توی مطلب قبل؛ چون این مسیریه که فقط با پرسیدن و تجربه کردن یاد گرفته می‌شه.

دیدگاهتان را بنویسید