Frage

Wenn ich nicht kopiere es falsch, der Code oben in der Tafel in einer Klasse von einem Student mit Hilfe / Korrekturen des Lehrers geschrieben wurde:

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

Wie Sie sehen können, gibt es eine Reihe von Kommentaren in allen Anweisungen und ich (glaube ich) die meisten von ihnen, was mich verwirrt, ist der Anruf, PUSHL / popl und ret Anweisungen. Ich verstehe nicht ganz, sie und ich verstehe nicht, auch das, was auf den Stapel passiert, und wo alle Datensätze zeigen. Grundsätzlich sind die Linien mit Kommentaren (//), die nichts auf sie geschrieben haben.

Es ist wirklich wichtig, ich verstehe, wie all dies funktioniert, hoffentlich können einige von euch etwas Licht auf all diesem Schlamassel.

Einige Hinweise auf meine Kommentare:

  • 0xsum: Das bedeutet nicht, die Adresse "Summe", wäre es unmöglich sein. Es nur ein Mittel zu verstehen, was ich rede, ohne die genaue Speicheradresse verwendet wird.
  • [sum = 0]:. Das bedeutet, dass in unserem C-Code, wird die variable Summe als 0 an dieser Stelle eingestellt werden
  • i + 1 => i:. Das bedeutet, dass wir den Wert von 'i' um eins sind erhöht wird und dass in der folgenden Zeile 'i' wird tatsächlich repräsentieren, dass inkrementierten Wert
War es hilfreich?

Lösung

auf einige der Code aussehen lassen:

main:
  call ini

Dies wird den Wert des Befehlszeigers auf den Stapel schieben (so dass Sie später auf diese Position im Code zurückgeben können), und an die Adresse des ini-Label springen. Die ‚ret‘ Anweisung verwendet den Wert auf dem Stapel gespeichert, aus dem Unterprogramm zurückzukehren.

Im Folgenden wird die Initialisierungssequenz eines Unterprogramms. Es speichert die Werte einiger Register auf dem Stapel und legt durch Kopieren des Stapelzeiger (ESP) zum Basiszeigerregister (EBP) einen Stapelrahmen auf. Wenn das Unterprogramm lokale Variablen aufweist, wird der Stapelzeiger dekrementiert wird Raum für die Variablen auf dem Stapel zu bilden, und der Basiszeiger wird verwendet, um die lokalen Variablen, die in dem Stapelrahmen zuzugreifen. Im Beispiel ist der einzige lokale Variable der (nicht verwendet) Rückgabewert.

Der Push-Befehl dekrementiert der Stapelzeiger (ESP) mit der Datengröße von dem, was zu schieben geht, dann an dieser Adresse den Wert speichert. Die Pop-Anweisung hat die umgekehrte, zuerst den Wert bekommen, dann inkrementiert den Stapelzeiger. (Beachten Sie, dass der Stapel wächst nach unten, so dass die Stapelzeiger-Adresse wird geringer, wenn der Stapel wächst.)

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)

Der Code folgt ein Standardmuster, so sieht es ein wenig umständlich, wenn es keine lokalen Variablen sind, und es ist ein unbenutzter Rückgabewert. Wenn es lokale Variablen eine Subtraktion verwendet werden würde, den Stapelzeiger statt Schieben eax zu verringern.

Im Folgenden ist die Austrittssequenz einer Unterroutine. Es stellt den Stapel in die Position vor der Stapelrahmen erstellt wurde, kehrt dann in den Code, der das Unterprogramm aufgerufen.

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

Als Antwort auf Ihre Kommentare:

Das EBX-Register geschoben und knallte es ist Wert zu bewahren. Der Compiler offenbar setzt immer diesen Code dort, wahrscheinlich, weil das Register sehr häufig verwendet wird, nur nicht in diesem Code. Ebenso ist ein Stapelrahmen immer durch Kopieren esp erstellt wird EBP auch wenn es nicht wirklich gebraucht wird.

Die Anweisung, die EAX schiebt nur dort den Stapelzeiger zu verringern. Es ist auf diese Weise für kleine Abnahmen durchgeführt, wie es ist kürzer und schneller als die Stapelzeiger subtrahiert wird. Der Raum, ist es für den Rückgabewert behält, wieder der Compiler anscheinend immer dies tut, auch wenn der Rückgabewert nicht verwendet wird.

In Ihrem Diagramm des ESP-Register konsequent zeigt vier Bytes zu hoch im Speicher. Denken Sie daran, dass der Stapelzeiger nach dem Drücken einen Wert verringert wird, so wird es weisen auf den Wert gedrückt wird, nicht auf den nächsten Wert. (Die Speicheradressen sind weg auch, es ist so etwas wie 0x600 statt 0x20, wie das ist, wo das Stack-Label deklariert ist.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top