Warum kann ich keine Vars auf den Stack legen???

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Warum kann ich keine Vars auf den Stack legen???
DAS:

long Print(long v)
{
_asm
{
sub esp, 4;
mov esp, v; // crash (access violation)
sub esp, 4;
mov esp, v;
add esp, 4[esp];
mov v, esp;
}

cout << v << "\n";

return 1;

}

funktioniert nicht (access violation). Weiß jemand, warum?


Evtl. klappt’s nicht, weil du den Stackpointer mit v überschreibst. Wenn du v auf den Stack kopieren willst, dann musst du ein mov [esp],v daraus machen. Ein push v würde auch ausreichen.

Bist du dir sicher, dass es schon bei der 2ten ASM-Zeile kracht? Ich würde einen Absturz erst bei add esp, 4[esp]; vermuten.


Steppen wir es doch mal…

_asm{
sub esp, 4; //hole 4 Byte auf dem Stack. (esp -=4)
mov esp, v; //schreibe v noch esp (esp = v) ist das so beabsichtigt?
sub esp, 4; //ziehe von esp nochmal 4 ab. (esp = v-4)
mov esp, v; //schreibe wieder v in den esp
add esp, 4[esp]; //schreibe den Wert aus esp (=v) nach esp+4 (das sit aber das v, das du übergeben hast +4.
mov v, esp; //schreibe den esp nach v
}

Das Prog macht gar keinen Sinn. und es schreibt auch nichts auf den Stack!
Du Überschribst den esp 2MAL mit einem Völlig willkürlichen (übergebenem) Wert und wunderst dich über nen acc viol ??


Vorsicht, da steht ein ADD in der vorletzten Zeile.
Ich will v zweimal auf den Stack legen, und dann die beiden Werte auf dem Stack addieren (v->2*v). Das Ergebnis der Addition soll wieder in v geschrieben werden. Sind vielleicht noch mehr Fehler drinnen, aber die kann ich nicht durch Trial & Error ausmerzen weil es access violation in der ZWEITEN Zeile gibt :frowning:

Ich will nicht den Stack Pointer überschreiben, ich will den Wert von v an die Adresse schreiben, auf die esp zeigt.


Ok ich hab ‚mov [esp], v‘ draus gemacht, aber dann sagt der Compiler: error C2415: Ungueltiger Operandentyp

Was mir Probleme bereitet ist, dass ich nicht richtig bei der M$ Schreibweise durchblicke.

Ist () bei VC einfach ?
Also ist
mov 4(%eax), (%ebx) aus dem Skript bei M$
mov [ebx], 4[eax]
?

Es gibt wirklich eine access violation in der zweiten Zeile.


Ich glaube das Problem liegt darin, wie der Compiler deine Variable v im inline Assembly auflöst. Entweder löst der Compiler das v einem Zugriff über den EBP oder über den ESP auf. Ich schätze er macht es über den ESP und optimiert den EBP weg, dann kann ich mir nämlich die Access Violation schon in Zeile 2 erklären.

Ich hab mal die MOV-Anweisung nachgeschlagen und diese erwartet mindestens ein Register oder Segmentregsiter, daher funktioniert mov [esp],v nicht, da v wohl über eine memory indirect Adressierung aufgelöst wird.

Nachfolgend mal 3 Varianten, die ich jetzt nicht getestet habe, die aber funktionieren sollten.

long Print(long v)
{
    _asm
    {
        push v;
        push v;
        add [esp], [esp + 4]; //kA ob das funktioniert; Ergebnis stünde in [esp]
        pop v;
        pop eax; // braucht man nur, um den Stack wieder herzustellen
    }
   
    cout << v << "\n";

    return 1;
}

Wenn du jetzt aber unnötige Speicherzugriffe vermeiden willst und auf Codeumfang Wert legst, dann könnte deine Funktion folgendermaßen aussehen:

long Print(long v)
{
    _asm
    {
        shl v,1;
    }
    cout << v << "\n";

    return 1;
}

Wenn du jetzt aber unbedingt die MOV-Befehle verwenden willst, musst du dein v zuerst in ein freies Register schieben und dann das Register auf den Stack.

long Print(long v)
{
    _asm
    {
        mov eax,v;
        sub esp,4;
        mov [esp],eax;
        sub esp,4;
        mov [esp],eax;
        add [esp], [esp + 4]; 
        mov eax, [esp];
        mov v, eax;
        add esp, 8;
    }
   
    cout << v << "\n";

    return 1;
}

Hi,

Variante 1:

M$ Compiler sagt: error C2415: Ungueltiger Operandentyp für pop v;

Variante 2:

funktioniert :gun:

Variante 3:

M$ Compiler sagt: error C2415: Ungueltiger Operandentyp für mov eax, [esp];

Das ist doch ein drecks-Compiler, da geht überhaupt nichts was Konvention ist. Trotzdem danke für die Vorschläge :gun:
Kannst du das mit dem Optimieren noch etwas genauer erklären?


Was zum Teufel…

Moment!

Variante 3: Der Compiler gibt zwar an, der Fehler wäre in der Zeile mov eax, [esp];, aber wenn ich die Zeile DAVOR (add [esp], [esp + 4]:wink: auskommentiere kompiliert’s. Also mag der M$ Compiler add [esp], [esp + 4]; nicht.

Ich habe sonst noch ausprobiert:

add [esp], 4[esp];
add [esp], [esp];
add [esp + 0], [esp + 4];

ergibt alles Fehler in der darauffolgenden Zeile :wand:


Ah jetzt ja!

Du hast ja gesagt:
"
Ich hab mal die MOV-Anweisung nachgeschlagen und diese erwartet mindestens ein Register oder Segmentregsiter, daher funktioniert mov [esp],v nicht, da v wohl über eine memory indirect Adressierung aufgelöst wird.
"

Darum darf man nicht zwei mal esp in einem mov benutzen. Das Nachfolgende funktioniert:

_asm
{
mov eax,v;
sub esp,4;
mov [esp],eax;
sub esp,4;
mov [esp],eax;
mov ebx, [esp + 4];
add [esp], ebx;
mov eax, [esp];
mov v, eax;
add esp, 8;
}

PS: WO hast du denn mov nachgeschlagen? In der VC++ 5.0 Hilfe habe ich nichts darüber gefunden.


Das Buch heißt „Assembler GE-PACKT“. Ansonsten einfach mal einen Blick in die Intel Prozessorhandbücher werfen, vorzugsweise ins 2te und 3te. Da stehen alle Befehle drin.