*Markus: (ASM) Wie spielen Stackpointer und Datengröße zusammen?

Hallo,

Es passt zwar nicht unbedingt hier rein, aber ich bin sicher, dass mich jemand diesbezüglich aufklären kann. Der folgende Code funktioniert:

segment .code

msg1 db "Message 1", 10
len1 equ $-msg1
msg2 db "Message 2", 10
len2 equ $-msg2

segment .text
global _start

_start:
mov eax, msg1
push eax
mov eax, msg2
push eax
mov eax, 4
mov ebx, 1
mov ecx, [esp+4]
mov edx, len1
int 0x80

mov eax, 1
int 0x80

Eines verstehe ich nicht. Wieso muss ich den Stackpointer gerade um vier erhöhen, um an den ersten String zu gelangen? Ich verstehe den Zusammenhang zwischen dem definierten Byte (das ja die Adresse des Strings enthält, wenn ich es richtig verstanden habe) und dem Platzverbrauch (offensichtlich 4 Adressen) auf dem Stack nicht.
Ich bin mal gespannt, wo mein Denkfehler ist.

--
http://www.apostrophitis.at
هؤا ﻻهى ثهى بعىيشةثىفشمهسفهسؤاثق مهىعءظفشمهﻻشىظنقهثلثقز
صشلف ثس تش ىهؤافو ةسظصهىيخصس شمس ﻻثفقهثﻻسسئسفثة ثهىغعسثفغفثىز
  1. Nachtrag:

    Offensichtlich stand ich wirklich auf dem Schlauch.
    Der Platz des kompletten Registers sind 32bit, also 4byte. Ich vergaß wohl, dass der Inhalt des kompletten Registers auf dem Stack abgelegt wird. Somit ist das mit den vier Bytes auch klar.

    --
    http://www.apostrophitis.at
    六 7東曲 人港ラ
  2. Hallo Markus,

    Es passt zwar nicht unbedingt hier rein, aber ich bin sicher, dass mich jemand diesbezüglich aufklären kann.

    ich will's versuchen. ;-)
    Lass mich zuerst noch mal laut denken: Im Lunux-Kernel ruft int 0x80 etliche Systemfunktionen auf, in eax wird die Funktionsnummer angegeben. Funktion #4 scheint eine Stringausgabe zu sein, bei der in ebx der Filehandle (hier 1=stdout), in ecx ein Zeiger auf den String und in edx die Länge des Strings übergeben wird.
    Also los.

    segment .code

    msg1 db "Message 1", 10
    len1 equ $-msg1
    msg2 db "Message 2", 10
    len2 equ $-msg2

    segment .text
    global _start

    _start:
    mov eax, msg1
    push eax                  ; lege einen Zeiger auf msg1 auf dem Stack ab
    mov eax, msg2
    push eax                  ; lege einen Zeiger auf msg2 auf dem Stack ab

    Bis hier war's Vorgeplänkel, das mit dem eigentlichen Funktionsaufruf nichts zu tun hat.

    mov eax, 4                ; Funktionsnummer
    mov ebx, 1                ; File-Handle (stdout)
    mov ecx, [esp+4]          ; Zeiger auf String (*)
    mov edx, len1             ; Stringlänge
    int 0x80                  ; Funktionsaufruf

    mov eax, 1                ; Funktionsummer für "Prozess beenden"
    int 0x80                  ; Funkion ausführen

    Eines verstehe ich nicht.

    Eines verstehe _ich_ nicht: Wozu legst du erst zwei Werte auf den Stack? Das erscheint mir völlig zweckfrei, und in diesem Fall unnötig. Da die beiden Werte nie wieder vom Stack abgeräumt werden, ist das genaugenommen sogar ein schwerwiegender Fehler, der nur deshalb keine Schutzverletzung (o.ä.) verursacht, weil das Programm danach sowieso beendet wird, ohne nochmal auf Werte von Stack (z.B. Rücksprungadressen) zurückzugreifen.

    Okay, zurück zur eigentlichen Frage: Nehmen wir mal an, der Stackpointer esp habe zu Beginn dieses Codestücks den Wert 00001000h.
    Bei einem push-Befehl wird erst der Stackpointer um die Anzahl der gepushten Bytes vermindert (hier 4, den es wird ein 32bit-Register gepusht), dann der gepushte Wert an die Adresse geschrieben, auf die der Stackpointer nun zeigt.
    Nach den beiden push-Befehlen haben wir also folgende Bestandsaufnahme:

    esp = 00000FF8h

    Stack:  00001000:  [Inhalt unbekannt]
             00000FFC:  Zeiger auf msg1
             00000FF8:  Zeiger auf msg2

    So. Wenn du jetzt 'mov  ecx,[esp+4] ausführst, dann lädst du den Wert, an der Speicheradresse esp+4, also im Moment 00000FFCh steht, ins ecx-Register. Das ist "zufällig" genau der Zeiger auf msg1, den du vorher per push-Befehl dort abgelegt hast.

    So isoliert erscheint mir dieses Code-Beispiel aber ziemlich sinnlos, vom vorher beschriebenen Stackfehler ganz abgesehen. Hast du das eventuell aus einem größeren Zusammenhang gerissen oder Teile herausgekürzt, ohne genau zu wissen, was du tust?

    Ich bin mal gespannt, wo mein Denkfehler ist.

    Ich hoffe, du erkennst ihn jetzt.

    So long,
     Martin

    --
    Wenn du beim Kochen etwas heißes Wasser übrig hast, friere es ein.
    Heißes Wasser kann man immer gebrauchen.
    1. Hallo,

      Eines verstehe _ich_ nicht: Wozu legst du erst zwei Werte auf den Stack? Das erscheint mir völlig zweckfrei, und in diesem Fall unnötig. Da die beiden Werte nie wieder vom Stack abgeräumt werden, ist das genaugenommen sogar ein schwerwiegender Fehler, der nur deshalb keine Schutzverletzung (o.ä.) verursacht, weil das Programm danach sowieso beendet wird, ohne nochmal auf Werte von Stack (z.B. Rücksprungadressen) zurückzugreifen.

      Das war auch nur ein Testbeispiel. Das Programm hat keinen tieferen Sinn. Bezüglich des Abräumens des Stacks hast du allerdings recht. Würde ich ein "add esp, 8" vor "pop eax, 1" schreiben, so würde das Programm m.M.n. "sauber" ausgeführt werden, falls ich das mit meinen Assembler-Newbiefähigkeiten richtig erkannt habe.

      So isoliert erscheint mir dieses Code-Beispiel aber ziemlich sinnlos, vom vorher beschriebenen Stackfehler ganz abgesehen. Hast du das eventuell aus einem größeren Zusammenhang gerissen oder Teile herausgekürzt, ohne genau zu wissen, was du tust?

      Nein, ich experimentiere nur ein wenig herum. Für das Schreiben eines Treibers reicht mein Wissen leider noch nicht aus. :)

      Ich hoffe, du erkennst ihn jetzt.

      Danke, jetzt ist es mir absolut klar.

      --
      http://www.apostrophitis.at
      六 7東曲 人港ラ
      1. Hi Markus,

        Würde ich ein "add esp, 8" vor "pop eax, 1" schreiben, so würde das Programm m.M.n. "sauber" ausgeführt werden, falls ich das mit meinen Assembler-Newbiefähigkeiten richtig erkannt habe.

        richtig, ja.

        Nein, ich experimentiere nur ein wenig herum. Für das Schreiben eines Treibers reicht mein Wissen leider noch nicht aus. :)

        Übung macht den Meister!  *g*

        Schönen Tag noch,
         Martin

        --
        "Life! Don't talk to me about life!"
          (Marvin, the paranoid android in Douglas Adams' "The Hitchhiker's Guide To The Galaxy"