آموزشاسمبلیبرنامه نویسی

معرفی زبان اسمبلی و ابزارهای مرتبط

اسمبلی چیست؟

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

این کدها به سختی قابلیت خوانایی داشتند و کار کردن با آنها سخت بود. به همین سبب زبان اسمبلی ابدا شد. این زبان در ابتدا تنها بر روی کاغذ بود و برای خوانده شدن توسط انسان بود و توسط اسمبلرها که در آن زمان خود آدم ها بودند با تجربه هر دو زبان تبدیل به کد ماشین می شدند تا اینکه برنامه ای ساختند که بتوانند این کد های اسمبلی را به صورت اتومات و نه دستی تبدیل به کد کامپیوتری کنند.

در حال حاضر اسمبلی سطح پایین ترین زبان موجود بعد از کد ماشین است. و البته باید بگوییم که اسمبلی در اصل یک زبان نیست از آنجایی که سینتکس های متفاوتی دارد. بخصوص برای معماری های مختلف cpu مانند IA32 (Intel Assembly 32 bit), ARM, MIPS, PowerPC و غیره…

با استفاده از زبان اسمبلی میتوانید به راحتی با سخت افزار ارتباط برقرار کنید. در معمول ترین حالت دو سخت افزار بسیار اساسی و مورد نیاز هستند. یکی RAM و دیگری خود CPU که این کدها را اجرا می کند. از RAM برای نگهداری داده ها استفاده می کنیم. هر چند در CPU حافظه های ذخیره سازی نهان بسیار کوچکی به نام ثبات وجود دارند که برای کاربردهای خاص ساخته شدند.

همینطور برای معماری Intel نیز دو سینتکس وجود دارد که یکی خود Intel است و دیگری AT&T. انتخاب هر کدام سلیقه ای است. لازم به ذکر است که ابزارهای GNU بصورت پیشفرض از سینتکس AT&T پشتیبانی می کنند.

یک نمونه کد Hello World در اسمبلی معماری IA64 با سینتکس Intel را در زیر میتوانید ببینید:

; compile and link with:
; nasm -f elf64 -o main.o main.c
; ld -o main main.o

section .text
global _start

_start:
; use linux write system call to write `message` content
; to stdout.

mov rax, 1 ; 1 is the write syscall number
mov rdi, 1 ; 1 is the file descriptor of stdout
mov rsi, message ; the address where content starts
mov rdx, [msgLen] ; the length of content
syscall ; call the system call (goes into kernel)

; terminate the program
mov rax, 0x3c ; 0x3c => 60 is the exit syscall number
mov rdi, 0 ; 0 as exit code (everything went fine)
syscall ; invoke the syscall (goes into kernel)

;----------------------------------------------------------------
section .data

message: db "Hello World!", 10
msgLen: dw 13

کاربردهای زبان اسمبلی

زبان اسمبلی برخلاف زبان های برنامه نویسی سطح بالا مانند سی، سی پلاس پلاس، جاوا و غیره بسیار راحت و بدون وابستگی می باشد که به محیط از پیش فراهم شده نیاز دارند. به همین دلیل زبان اسمبلی در پروسه بوت سیستم بسیار کاربرد دارد و تنها راه حل موجود است. در مرحله بوت سیستم با اسمبلی برنامه مینویسند که بتواند عملیات هایی را برای آماده سازی cpu و RAM انجام دهد مانند تعریف GDT و بردن cpu از حالت real mode 16 bit به protected mode 32 bit و در نهایت به long mode 64bit و تنظیم نحوه دسترسی به حافظه ها و غیره..

کاربرد دیگر اسمبلی زمانی است که میخواهید overhead هایی که زبان های برنامه نویسی سطح بالا تولید می کنند را حذف کنید اینکار تاثیر بسزایی در performance دارد. همینطور خیلی اوقات نمی توانید به بعضی feature های cpu دسترسی پیدا کنید و معمولا بخاطر performance بهتر است از آنها استفاده کنید. مانند دستورات مربوط کنترل virtual machine و یا استفاده مستقیم از رجیسترهای (FPU (Floating Point Unit. یا بعنوان مثال bit shift چرخشی در زبان سی وجود ندارد اما در زبان اسمبلی وجود دارد که توسط cpu خیلی سریع اجرا میشود: ROR

برای مهندسی معکوس در اکثر موارد دانستن اسمبلی نیاز است زیرا نمیتوان کد ماشین را به بعنوان مثال زبان سی برگداند ولی میتوان کد ماشین را به اسمبلی تبدیل کرد.

بدافزار نویس ها نیز استفاده بسزایی از اسمبلی می کنند زیرا مبهم سازی کد در زبان اسمبلی بسیار آسانتر است. در زبان اسمبل از آنجایی که ارتباط مستقیمی به زبان ماشین دارد تغییر کد بصورت runtime بسیار راحت تر می باشد که به اینکار morphism میگویند. دو مدل morphism که در بدافزارهای حرفه ای به چشم میخورند polymorphism و metamorphism هستند که برای تغییر حالت و دور ماندن از شناسایی توسط آنتی ویروس ها بکار می روند.

در اکسپلویت کردن برنامه ها برای تزریق کد ماشین نیز نیاز است از اسمبلی استفاده شود بخاطر نداشتن overhead ها و مستقیم تبدیل شدن به کد ماشین.

ابزارهای برنامه نویسی

برای کامپایل کردن:

  • nasm: یکی از کار‌آمدترین و ساده ترین برنامه ها برای کامپایل اسمبلی بخصوص سینتکس اینتل می باشد.
  • masm: اسمبلر مایکروسافت که تنها 16bit و 32bit را پشتیبانی می کند. برای 64bit از ML64 استفاده کنید.
  • fasm: اسمبلری ساده با پشتیبانی کامل ویندوز و لینوکس همینطور با سینتکس اضافه ساده و پرکاربرد و از این اسمبلر برای ساخت فایل های غیر اجرایی با ساختار خاص نیز استفاده بسیاری می شود.
  • gas: اسمبلر گنو بطور پیشفرض در اکثر توزیع های لینوکسی موجود می باشد و همانطور که قبلا قید شد در ابزارهای گنو از سینتکس at&t پشتیبانی می شود هرچند که معمولا از intel هم پشتیبانی میکنند ولی باید آنرا مستقیما مشخص کنید.

برای لینک کردن:

  • ld: بصورت پیشفرض در لینوکس که فایل قابل اجرا elf میسازد.
  • LINK.exe: برای ویندوز که فایل قابل اجرا exe میسازد.

چند دستور مهم در اسمبلی Intel

; copy value from source to dest: mov dest, source
; c example: dest = source;
; dest can be memory or register
; source can be memory or register or value
; source and dest can not be both memory at same time
mov eax, ebx ; copy ebx to eax, valid
mov eax, 0x447 ; copy value 0x447 to eax, valid
mov [ebp-0x20], eax ; copy eax to memory pointed by ebp at offset -0x20, valid
mov edx, [ebp-0x4] ; copy memory pointed by ebp at offset 0x4 to edx, valid
mov [ebp-0x20], [ebp-0x4] ; copy memory to memory, invalid!

; add instruction: add dest, data
; c example: dest += data;
; dest can be memory or register
; data can be register or value
add eax, 0x90
add eax, edx
add [ebp-0x20], 0x50
add [ebp-0x24], eax

;; instructions sub, mul, div, and, or, xor are all as add instruction

; inc and dec: inc dest, dec dest
; c example: dest++; dest--;
; dest can be register or memory
inc eax
dec eax
inc [esp+0x4]
dec [esp+0x16]

; compare : cmp dest, source
; cmp sets FLAGS register and can be further used for other
; instructions like jmp derivatives
; c example : dest == source, dest <= source, dest > source, etc..
; dest can be register or memory
; source can be value, regiter or memory
; dest and source can't be memory at same time
cmp eax, 0x20
cmp [ebp-0x8], 0x4
cmp eax, edx
cmp eax, [ebp-0x8]
cmp [ebp-0x8], edx

; jump to somewhere else: jmp place
; c like: goto place
; jmp moves to place pointer, so unlike c, it doesn't need to be label
; place can be offset, address, register, memory
jmp eax
jmp 0x80444
jmp [ebp-0x20]

jnz eax ; jump if flag zero is not set
jz ; jump if flag zero is set
je ; jump if comparison is equal
jne ; jump if not equal
jp ; jump if parity
jle ; jump if less or equal
jge ; jump if greater or equal
; and many others...

برای دستورات بیشتر و نحوه استفاده آنها میتوانید به manual اینتل یا سازنده معماری مورد نظر مراجعه کنید. یا از این لینک نیز میتوانید استفاده کنید که بطور خیلی خلاصه طرز کار تعدادی از دستورات اینتل x86 را توضیح داده است.

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

امیدوارم این پست برای شما مفید واقع شده باشد.

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

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *


دکمه بازگشت به بالا