2009-09-08 16 views
5

Lassen Sie uns sagen, dass wir die folgende C++ Code haben:Definieren einer Variable in C++ Inline-Assembler

int var1; 

__asm { 
    mov var1, 2; 
} 

Nun, was ich möchte, ist wissen, wenn ich nicht var1 außerhalb der __asm ​​Richtlinie definieren wollte, Was müsste ich tun, um es hinein zu legen? Ist es überhaupt möglich?

Dank

Antwort

12

Um dies zu tun, müssen Sie eine "nackte" Methode mit _declspec (nackt) erstellen und sich den Prolog und den Epilog schreiben, die normalerweise vom Compiler erstellt werden.

Das Ziel eines Prologs ist:

  • einrichten EBP und ESP
  • Reserveraum auf Stapel für lokale Variablen
  • speichern Register, die im Körper der Funktion geändert werden sollte

Ein Epilog hat:

  • wiederherstellen die gespeicherte Registerwerte
  • den reservierten Raum für lokale Variablen aufzuräumen

Hier ist ein Standard-Prologs

push  ebp    ; Save ebp 
mov   ebp, esp   ; Set stack frame pointer 
sub   esp, localbytes ; Allocate space for locals 
push  <registers>  ; Save registers 

und ein Standard-Epilog:

pop   <registers> ; Restore registers 
mov   esp, ebp  ; Restore stack pointer 
pop   ebp   ; Restore ebp 
ret      ; Return from function 

Ihre lokale Variablen beginnt dann bei (ebp - 4) und geht nach unten zu (ebp - 4 - localbytes). Die Funktionsparameter beginnen bei (ebp + 8) und gehen nach oben.

3

Es unmöglich, ein C-Variable in Assembler zu erstellen: der C-Compiler hat etwa die Größe (dh seine Art und Adresse), zu wissen, was bedeutet, dass es in dem C-Code angegeben werden muss.

Es kann auf in Assembler über extern Deklarationen in C definierte Symbole zugegriffen werden. Dies funktioniert jedoch nicht bei Variablen mit automatischer Speicherdauer, da diese keine feste Adresse haben, sondern relativ zur Basis referenziert sind Zeiger.

Wenn Sie nicht auf die Variablen außerhalb des Blocks asm zugreifen möchten, können Sie den Stack zum Speichern von lokalen Assembler-Daten verwenden. Denken Sie daran, dass Sie den Stapelzeiger auf den vorherigen Wert wiederherzustellen, wenn die asm Block verlassen, zB

sub esp, 12  ; space for 3 asm-local 32bit vars 
mov [esp-8], 42 ; set value of local var 
[...] 
push 0xdeadbeaf ; use stack 
[...]    ; !!! 42 resides now in [esp-12] !!! 
add esp, 16  ; restore esp 

Wenn Sie nicht die relativen Adressen der lokalen Variablen ändern möchten, wenn Sie den Stapel manipulieren (dh push oder pop), Sie müssen einen Stack-Frame erstellen (dh die Basis des Stacks in ebp speichern und Locals relativ zu diesem Wert adressieren), wie in cedrou's answer beschrieben.

+0

Sind Sie sicher, esp sub, wird 3 Raum gibt für drei 32-Bit-vars? Ich hatte die Idee, dass ich für jede 32-Bit-Var-Variante vier von vier nehmen müsste. –

+0

Zumindest C++ definiert es intern wie folgt: var_4 = dword ptr -4 –

+0

du hast Recht - solltest du diese Fragen spät nachts nicht beantworten;) – Christoph

3

Lokale Variablen zugewiesen und befreit von dem verfügbaren Speicherplatz auf dem Call-Stack über das ESP-Register zu manipulieren, das heißt:

__asm 
{ 
    add esp, 4 
    mov [esp], 2; 
    ... 
    sub esp, 4 
} 

Im Allgemeinen ist dies gehandhabt besser durch einen „Stapelrahmen“ für die aufrufende Funktion zur Gründung statt und dann lokale Variablen zugreifen (und Funktionsparameter) Offsets im Rahmen verwenden, anstatt direkt das ESP registrieren zu verwenden, das heißt:

__asm 
{ 
    push ebp 
    mov ebp, esp 
    add esp, 4 
    ... 
    mov [ebp-4], 2; 
    ... 
    mov esp, ebp 
    pop ebp 
} 
Verwandte Themen