سؤال

إلا إذا نسخت خطأ رمز أعلاه هو مكتوب في السبورة في الصف من قبل الطالب مع مساعدة/تصويبات المعلم:

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 ، حيث كومة التسمية المعلنة.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top