مشكلة التجميع مع البرنامج البسيط
-
29-09-2019 - |
سؤال
أحاول تعلم التجميع من الصفر. لقد قرأت قليلاً ، لكن حتى البرنامج البسيط التالي الذي وجدته في كتاب مرجعي قد صعدني:
section .data
msg db "Hello!", 0xa
len equ $ - msg
section .text
global _start
_start:
move edx, len
move ecx, msg
move ebx, 1
move eax, 4
int 0x80
move ebx, 0
move eax, 1
int 0x80
يبدو أن هذا من المفترض أن يطبع هذا "مرحبًا". لكني لا أعرف حتى ما يحدث في أي من المراحل. وضعت المرحلتان الأوليان طول الرسالة والسيطات في سجلين ، لم يتم استخدامها مرة أخرى. أنا لا أفهم لماذا.
لا أعرف لماذا هناك حاجة إلى أربعة سجلات مختلفة.
المحلول
int 80
هي آلية في بعض*أ أنظمة التشغيل التي تشبه UNIX لإجراء مكالمات النظام.
لهذه المكالمات ، يتم استخدام السجلات لقيم محددة. من syscalls
ملف:
0 STD NOHIDE { int nosys(void); } syscall nosys_args int
1 STD NOHIDE { void exit(int rval); } exit rexit_args void
2 STD POSIX { int fork(void); }
3 STD POSIX { ssize_t read(int fd, void *buf, size_t nbyte); }
4 STD POSIX { ssize_t write(int fd, const void *buf, size_t nbyte); }
يمكنك رؤية أن الرقم 4 هو write
اتصل وتحتاج إلى ثلاثة معلمات أخرى. رقم 1 هو exit
ويحتاج فقط رمز الإرجاع.
عند إجراء المكالمة ، eax
هو syscall الذي تصنعه أثناء ebx
, ecx
و edx
هي المعلمات الثلاثة (على افتراض أنها جميعها مطلوبة - exit
على سبيل المثال لا يحتاج سوى واحد).
لذلك ، يمكنك التعليق على الرمز على النحو التالي:
move edx, len ; length of message (nbyte).
move ecx, msg ; message to print (buf).
move ebx, 1 ; file handle 1, stdout (fd).
move eax, 4 ; write syscall.
int 0x80 ; do it.
move ebx, 0 ; exit code (rval).
move eax, 1 ; exit syscall.
int 0x80 ; do it.
*أ: قدمت الإصدارات اللاحقة من Linux واجهة جديدة يمكنها استخدام طرق مختلفة بناءً على أفضل سرعة. على سبيل المثال ، بعض رقائق Intel أسرع بكثير إذا كنت تستخدم sysenter
عوضا عن int 80
.
نصائح أخرى
IIRC int 0x80
يتم استخدام التعليمات لاستدعاء syscall باستخدام متجه المقاطعة. في مثالك القيم في ebx
و eax
تستخدم لتحديد أي syscall سوف تتصل (ربما عملية الطباعة على stdout).
يعرف Syscall عن طريق القبول edx
و ecx
يجب أن تحتوي على ما سيتم طباعته.
على العديد من الأنظمة ، int 80h هل استدعاء النظام بوابة. رقم Syscall في eax
. ebx
, ecx
و edx
تحتوي على معلمات إضافية:
move edx, len
move ecx, msg
move ebx, 1 ; fd 1 is stdout
move eax, 4 ; syscall 4 is write
int 0x80 ; write(1, msg, len)
move ebx, 0
move eax, 1 ; syscall 1 is exit
int 0x80 ; exit(0)
عند استدعاء مكالمة النظام ، "int" ذاكري ، يتم إنشاء انقطاع النظام. إنه "يقفز" كيندا إلى وظيفة النظام ، والتي ، في هذه الحالة ، تطبع الإخراج (يعتمد على EAX).
يستخدم هذا الانقطاع كل هذه السجلات لمعرفة ما يجب القيام به. تقرأ المقاطعة EAX ، تحقق من الوظيفة التي تريدها وتستخدم السجلات الأخرى للقيام بذلك.
EAX هو رقم الوظيفة ، 4 يعني sys_write ، الذي يكتب سلسلة إلى واصف دفق/ملف.
الآن تعرف أنك تريد كتابة شيء ما إلى مكان ما ، ثم يستخدم السجلات الأخرى لتلك المعلومات.
بالنسبة إلى EAX = 4 و int 0x80 ، هذا هو المعنى للسجلات الأخرى:
EBX = الإخراج (1 = stdout)
ECX = عنوان السلسلة
edx = طول السلسلة
يمكنك قراءة هذا:
http://www.intel.com/assets/ja_jp/pdf/manual/253665.pdf
القسم 6.4 لديه بعض الأشياء حول المقاطعات والاستثناءات.
ويمكنك البدء في كتابة رمز تجميع Intel 80x86 ، وهو أبسط وأسهل في الفهم ، إليك بعض الروابط:
Mnemonics/Code Tables Cheatsheet:http://www.jegerlehner.ch/intel/
بعض مواقع المقدمة:http://mysite.du.edu/~etuttle/math/8086.htmhttp://www.malware.org/teaching/assembly.htm