بسمه تعالی مبحث اسمبلی در لینوکس شاید یکی از موضوعاتی باشد که بسیار بر روی آن کم کار شده است. شاید بیشترین علت آن عدم وجود نیازی چون درایورهای نوشته شده توسط اسمبلی در داس باشد. چرا که تقریبا تمام کارها توسط زبانهایی چون cدر لینوکس انجام میشود و آنجا که صحبت از سرعت به میان می آید در نوشتن بوت لودر ،کرنل و سرویسی چون httpdاسمبلی به کار می آید .و احتمال همین باعث میشود که در ابتدای هر کدام از مقالت نوشته شده در این زمینه بخش عظیمی به تلش جهت منصرف کردن شما از نوشتن اسمبلی در لینوکس می کند. به هر حال در زیر مجالی را به لینوکس اسمبلی اختصاص داده ایم: یکی از مهمترین تفاوتهای اسمبلی داس و لینوکس این است که در داس بیشتر کارها با interrupt داس int 21hد و اینتراپتهای سرویس biosمانند int 10hو int 16hصورت میگیرد در حالی که در لینوکس تمام این کارها توسط کرنل انجام میشود.همه چیز توسط ““kernel system calls صورت میگیرد و شما میتوانید کرنل را به وسیله int 80hصدا بزنید(.همچنین میتوانید از کتابخانه های libcاستفاده کنید که ممکن است راحت تر باشد اما برنامه نوشته شده را وابسته به کتابخانه های مذکور میکند ) .یک چیز شگفت آور در مورد لینوکس این است که نسبت به داس کمتر میباشند(حدود (190ولی کارآتر هستند .سیستم کال های لینوکس فایلها را ایجاد میکنند و پروسه ها را تحویل میگیرند وکارهای مفیدی دیگری را انجام میدهند. کامپایلر های اسمبلی در لینوکس بسایر زیادتر از آنند که بخواهیم مجالی را به بررسی هر کدام اختصاص دهیم .که این در واقع یکی از مزایای open sourceمیباشد که برای انجام هر کار چندین نرم افزار جدا موجود میباشد. در زیر لیستی را از چندین اسمبلر لینوکس میبینیم سپس به بررسی GASو GCCو NASM میپردازیم: GCC Inline assembly.1 GAS.2 NASM.3 AS86.4 YASM.5 FASM.6 (OSIMPA(SHASM.7 TDASM.8 HLA.9 TALK.10 FREE PASCAL.11 Win32Forth assembler.12 Terse.13 در میان اسمبلرهای فوق که هر یک Syntaxخود را دارا میباشد از اسمبلرهای 1-4استفاده بیشتری میشود و ما بقی شهرت چندانی ندارند .حال آنکه HLAدر واقع high level assemblyبوده و دارای syntaxای مشابه زبانهایی چون Cمیباشد.
کتاب Art of assemblyکه یکی از کتابهای مرجع جهت آموزش زبان اسمبلی میباشد در نسخه موجود لینوکسی خود از این syntaxاستفاده کرده است. قبل از ادامه اجازه دهید دو syntaxمختلف AT&Tو Intelرا که بیشترین Syntaxهای مورد استفاده در لینوکس میباشند بررسی کنیم: :AT&Tشباهت زیادی به Intel syntaxدارد با تفاوتهای خاص زیر: در syntaxاینتل در دستورتی چون movابتدا destو سپس sourceمی آید Mov ax,3 در حالی که در AT&Tاین برعکس است و ابتدا sourceو سپس destinationمی آید .برای دستورات movو Addو ...باید نوع متغیر را مشخص کرد مثل در صورتی که متغیر ما از نوع longمیباشد باید از دستور movlاستفاده کرد .در ابتدای نام رجیستر ها باید از علمت % و ابتدای نام ثابت ها باید از $استفاده کرد .و کامنت ها با #به نمایش می آیند. Movl $0,%ebx PUT 0 IN EBX# همچنین فایل های اسمبلی در این Syntaxبه صورت s.ذخیر میشوند. :Intel syntax با این syntaxبه اندازه کافی آشنا میباشید . :GCC Inline assembly Gccبه عنوان یکی از کمپایلرهای مشهور لینوکس که زبانهای مختلفی را پشتیبانی میکند اسمبلر ناشناخته ای نیست GCC .تا چندی پیش تنها از AT&T Syntaxپشتیبانی میکرد .به طوری که هر جا اسم gccبه میان می آید صحبت از AT&T Syntaxبه میان می آید) .همچنین گاه از Inline assemblyصحبت به میان می آید .که از لحاظ syntaxهمان AT&T syntax میباشد( اما در ورژن های اخیر gccپشتیبانی Intel syntaxرا اضافه کرده است .که متاسفانه داکیومنت مفیدی در این رابطه پیدا نکردم .بهترین مزیت gccنسبت به دیگر اسمبلر زمانی است که از کدهای اسمبلی در میان کدهای زبان دیگری همچون Cاستفاده کرده ایم که کار ما را راحت میکند. :GAS یکی از اسمبلر های مشهور و محبوب لینوکس میباشد که مخفف GNU Assemblerبوده و بر پایه GCCمیباشد .این اسمبلر برای Syntax AT&Tبوده ولی اخیرا پشتیبانی Intel syntax را اضافه کرده است .که باید از دایرکتیو Intel syntax.استفاده شود .متاسفانه هنوز کتابخانه های مربوطه documentنشده اند. :NASM Net wide Assembler projectکه یک اسمبلر i386میباشد که توسط cنوشته شده است. Syntaxمورد استفاده Intel Syntaxمیباشد و فرمت های objectفایل زیر را پشتیبانی میکند: Bin,aout,coff,elf,as86,obj)DOS(,win32,rdf Nasmبا parserنوشته شده دستی خود سریعتر از GASمیباشد ولی برخی ساختارها را پشتیبانی نمی کند .به هر حال برای Intel Syntaxاین اسمبلری میباشد که پیشنهاد میشود.
. میپردازدNasm syntax باassembly این نوشته به بررسی برنامه نویسی
: hello world یک برنامه :AT&T Syntax data # section declaration. :msg string "Hello, world!\n" # our dear string. Len = . -- msg # length of our dear string text # section declaration. we must export the entry point to the ELF linker or # global _start # loader. They conventionally recognize _start as their. .entry point. Use ld --e foo to override the default # :start_ write our string to stdout # movl $len,%edx # third argument: message length movl $msg,%ecx # second argument: pointer to message to write )movl $1,%ebx # first argument: file handle )stdout )movl $4,%eax # system call number )sys_write int $0x80 # call kernel and exit # movl $0,%ebx # first argument: exit code )movl $1,%eax #system call number )sys_exit int $0x80 # call kernel
:Intel Syntax msg db "Hello, world!",0xa ;our dear string len equ $ - msg ;length of our dear string section .text ;section declaration we must export the entry point to the ELF linker or ; global _start ;loader. They conventionally recognize _start as their .entry point. Use ld -e foo to override the default ; :start_
; write our string to stdout mov edx,len ;third argument: message length mov ecx,msg ;second argument: pointer to message to write (mov ebx,1 ;first argument: file handle (stdout (mov eax,4 ;system call number (sys_write int 0x80 ;call kernel ; and exit mov ebx,0 ;first syscall argument: exit code (mov eax,1 ;system call number (sys_exit int 0x80 ;call kernel کامپایل کردن (اسمبل کردن( برنامه در لینوکس: برای کامپایل کردن برنامه با Intel syntaxاز دستور زیر استفاده کنید: $ nasm −f elf hello.asm
خروجی برنامه به فرمت elfخواهد بود برای کامپایل کردن برنامه با AT&T Syntaxاز دستور زیر استفاده کنید: $ as −o hello.o hello.S
دستور ذکرشده تنها فایل objectرا تولید میکند برای لینک کردن فایل مذکور و ساختن فایل قابل اجرا باید از دستور ldاستفاده کرد ld .لینکر استاندارد محیط لینوکس میباشد توجه داشته باشید که در gccلینک کردن به صورت خودکار انجام میشود و در صورتی که نخواهید که عمل لینک شدن انجام شود باید از سویچ های مربوطه استفاده کنید. $ ld −s −o hello hello.o
سویچ – oبه ldمیگوید که نام فایل خروجی را helloبگذارد. Debugکردن برنامه در :Linux برای debugکردن یک برنامه در محیط تکست میتوان از gdbاستفاده کرد و در محیط gui نیز میتوان از dddکه ربط گرافیکی gdbمیباشد استفاده کرد .برای استفاده از gdbبرای debugکرن یک برنامه که میخواهید توسط gccکامپایل کنید از سویچ g-استفاده کنید. Debuggerهای زیادی برای محیط لینوکس وجود دارد که میتوانید از آنها استفاده کنید . همچنین محیط برنامه نویسی Kdevelopابزار بسیار قوی ای جهت نوشتن برنامه در لینوکس را برای شما فراهم میکند و debuggerخوبی را نیز در اختیر شما قرار میدهد.
ورودی و خروجی در :Linux assembly برخی استفده از libcرا تنها راه بیان میکنند و استفاده مستقیم از system callها را راه خوبی نمیدانند این در حالی است که در بیشتر موارد تنها کار اضافه ای که در توابع libcانجام میشود چک کردن برخی از پارامترها و ...میباشد و سپس system callمذکور صدا زده میشود. برای استفاده از system callها : .1شماره sysyemcallرا در رجیستر eaxقرار دهید .2پارامترهای دیگر را در رجیسترهای ebxو ecxو ...قرار دهید .3کرنل را صدا بزنید()int 80h .4نتیجه در رجیستر eaxبرگردانده میشود. برای مثال در انتهای برنامه کد زیر نوشته میشود: ; The exit syscall number ; Have an exit code of 0 ; call kernel
eax,1 ebx,0 80h
mov mov int
نوشن ماکرو در :NASM :Single line macros در اسمبلی علمت %در ابتدای یک دایرکتیو آن را به preprocessorبه عنوان یک preprocessor directiveمعرفی میکند . برای داشتن یک ماکرو در یک خط مانند زبان cمیتوانیم از defineاستفاده کنیم ))define% & %define ctrl 0x1F :multiple line macros تعریف ماکروهای multiple lineشباهت بیشتری به تعریف ماکرو در MASMدارد تعریف ماکرو با macro%شروع شده و با endmacro%پایان میپذیرد %macro prologue 1 push ebp mov ebp,esp sub esp,%1 %endmacro