الجمعية:Y86 كومة ، pushl/popl و ret تعليمات
سؤال
إلا إذا نسخت خطأ رمز أعلاه هو مكتوب في السبورة في الصف من قبل الطالب مع مساعدة/تصويبات المعلم:
int array[100], sum, i;
void ini() {
for(i = 0; i < 100; i++)
array[i] = i;
}
int main() {
ini();
sum = 0;
for(i = 0; i < 100; i++)
sum += array[i];
}
.pos 0
irmovl Stack, %esp
rrmovl Stack, %ebp
jmp main
array:
.pos 430
sum: .long 0
i: .long 0
main:
call ini //
irmovl $0, %eax // %eax = 0
irmovl sum, %esi // %esi = 0xsum
rmmovl %eax, 0(%esi) // 0(%esi) = %eax <=> 0(0xsum) = 0 [sum = 0]
rmmovl %eax, 4(%esi) // 4(%esi) = %eax <=> 4(0xsum) = 0 [i = 0]
compare:
irmovl $100, %ebx // %ebx = 100
subl %eax, %ebx // %ebx = %ebx - %eax <=> %ebx = 100 - i
jle finish // Jumps to "finish" if SF=1 pr ZF=0
mrmovl 0(%esi), %edx // %edx = 0(%esi) <=> %edx = 0(0xsum) = sum
addl %eax, %edx // %edx = %edx + %eax <=> %edx = sum + i => sum
rmmovl %edx, 0($esi) // 0(%esi) = %edx <=> 0(0xsum) = sum
irmovl $1, %ecx // %ecx = 1
addl %ecx, %eax // %eax = %eax + %ecx <=> %eax = i + 1 => i
rmmovl %eax, 4(%esi) // 4($esi) = %eax <=> 4(0xsum) = i
jmp compare // Jumps unconditionally to "compare"
ini:
pushl %ebp //
rrmovl %esp, %ebp //
pushl %ebx //
pushl %eax //
irmovl $0, %eax // %eax = 0
rmmovl %eax, -8(%ebp) //
ini_compare:
irmovl $100, %ecx // %ecx = 100
subl %eax, %ecx // %ecx = %ecx - %eax <=> %ecx = 100 - i
jle ini_finish // Jumps to "ini_finish" if SF=1 pr ZF=0
rrmovl %eax, %ebx // %ebx = %eax <=> %ebx = i
addl %eax, $ebx // %ebx = %ebx + %eax <=> %ebx = i + i = 2i
addl %ebx, %ebx // %ebx = %ebx + %ebx <=> %ecx = 2i + 2i = 4i
rmmovl %eax, array(%ebx) // array(%ebx) = %eax <=> array(0x4i) = i
irmovl %1, %ecx // %ecx = 1
addl %ecx, %eax // %eax = %eax + %ecx <=> %eax = i + 1 => i
rmmovl %eax, -8(%ebp) //
jmp ini_compare // Jumps unconditionally to "ini_compare"
ini_finish:
irmovl $4, %ebx //
addl %ebx, %esp //
popl %ebx //
popl %ebp //
ret //
.pos 600
Stack .long 0
كما ترون, هناك مجموعة من التعليقات في التعليمات وحصلت على (على ما أظن) معظمهم ما يحيرني هو الدعوة ، pushl/popl و ret التعليمات.أنا لا أفهم تماما لهم و أنا أيضا لا أفهم ما يحدث كومة حيث تشير سجلات.في الأساس, خطوط مع تعليقات (//) أن لا يكون أي شيء مكتوب عليها.
انه من المهم حقا لا أفهم كيف يعمل كل هذا ، ونأمل أن البعض منكم يمكن أن يلقي بعض الضوء على كل هذه الفوضى.
بعض الملاحظات على تعليقاتي:
- 0xsum: هذا لا يعني أن العنوان هو "مجموع" ، سيكون من المستحيل.انها مجرد وسيلة لفهم ما أتحدث عنه دون استخدام نفس عنوان الذاكرة.
- [sum = 0]: وهذا يعني أن لدينا في التعليمات البرمجية C, متغير المبلغ سوف تكون على النحو 0 في هذه المرحلة.
- أنا + 1 => أنا: هذا يعني أننا تزايد قيمة " أنا "من جانب واحد في السطر التالي" أنا " سوف تمثل في الواقع أن زيادة القيمة.
المحلول
دعونا نلقي نظرة على بعض من التعليمات البرمجية:
main:
call ini
هذا دفع قيمة مؤشر التعليمة إلى المكدس (حتى يمكنك بعد ذلك العودة إلى هذا الموقف في القانون) ، والقفز إلى عنوان ini التسمية.إن 'المؤسسة' تعليمات يستخدم القيمة المخزنة على المكدس في العودة من الروتين الفرعي.
وفيما يلي initialisation تسلسل روتين فرعي.فإنه يحفظ قيم بعض السجلات على المكدس و يضع الإطار المكدس عن طريق نسخ مؤشر مكدس (esp) إلى قاعدة المؤشر سجل (ebp).إذا كان روتين وقد المتغيرات المحلية ، مؤشر مكدس هو decremented لإفساح المجال أمام المتغيرات على المكدس ، وقاعدة مؤشر يستخدم للوصول إلى المتغيرات المحلية في الإطار المكدس.في المثال الوحيد المحلية هو متغير (غير المستخدمة) قيمة الإرجاع.
دفع التعليمات decrements مؤشر مكدس (esp) مع البيانات حجم ما سوف تكون دفعت ، ثم يخزن قيمة في هذا العنوان.تعليمات pop لا العكس ، أولا الحصول على قيمة ، ثم الزيادات مؤشر مكدس.(لاحظ أن كومة ينمو أسفل ، وذلك مؤشر مكدس عنوان يحصل على أقل عندما كومة ينمو.)
ini:
pushl %ebp // save ebp on the stack
rrmovl %esp, %ebp // ebp = esp (create stack frame)
pushl %ebx // save ebx on the stack
pushl %eax // push eax on the stack (only to decrement stack pointer)
irmovl $0, %eax // eax = 0
rmmovl %eax, -8(%ebp) // store eax at ebp-8 (clear return value)
رمز يتبع نمط موحد ، بحيث يبدو محرجا بعض الشيء عندما لا يكون هناك المتغيرات المحلية و هناك غير المستخدمة قيمة الإرجاع.إذا كان هناك المتغيرات المحلية على الطرح سوف تستخدم في إنقاص مؤشر مكدس بدلا من دفع eax.
وفيما يلي تتابع الخروج من روتين فرعي.فإنه يعيد المكدس إلى الموقف قبل المكدس الإطار تم إنشاء, ثم يعود إلى التعليمات البرمجية التي تسمى روتين فرعي.
ini_finish:
irmovl $4, %ebx // ebx = 4
addl %ebx, %esp // esp += ebx (remove stack frame)
popl %ebx // restore ebx from stack
popl %ebp // restore ebp from stack
ret // get return address from stack and jump there
ردا على التعليقات الخاصة بك:
على ebx السجل دفعت برزت للحفاظ على انها قيمة.المترجم على ما يبدو دائما يضع هذا الكود هناك, ربما لأن التسجيل هو شائع جدا ، ليس فقط في هذا القانون.وبالمثل إطار مكدس دائما إنشاؤها بواسطة نسخ esp إلى ebp حتى لو انها ليست في حاجة حقا.
التعليمات التي يدفع eax هناك فقط لإنقاص مؤشر مكدس.يتم ذلك بهذه الطريقة الصغيرة decrements كما انها أقصر وأسرع من طرح مؤشر مكدس.مساحة أنه الاحتياطيات من أجل عودة القيمة مرة أخرى المترجم على ما يبدو دائما يفعل هذا حتى إذا كانت قيمة الإرجاع هي لم تستخدم.
في الرسم البياني الخاص بك esp السجل باستمرار لافتا أربعة بايت عالية جدا في الذاكرة.تذكر أن مؤشر مكدس هو decremented بعد دفع قيمة ، لذلك سوف نشير إلى قيمة ما دفعت ، ولا إلى القيمة.(عناوين الذاكرة هي وسيلة قبالة كما انها شيء مثل 0x600 بدلا من 0x20 ، حيث كومة التسمية المعلنة.)