2013-10-15 5 views
5

Ich schreibe Code, um vorübergehend meinen eigenen Stapel für Experimente zu verwenden. Dies funktionierte, wenn ich die Inline-Assemblierung in Literalformat verwendete. Ich habe die variablen Standorte als Offsets von ebp hart codiert. Ich wollte jedoch, dass mein Code funktioniert, ohne Speicheradressen fest codieren zu müssen. Daher habe ich GCCs EXTENDED INLINE ASSEMBLY untersucht. Was ich habe, ist die folgende:

volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER; 
volatile intptr_t old_stack_ptr = 0; 
asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

Der Punkt dieser ist, zuerst den Stapelzeiger in die Variable old_stack_ptr zu speichern. Als nächstes wird der Stapelzeiger (% esp) mit der Adresse überschrieben, die ich in new_stack_ptr gespeichert habe.

Trotzdem fand ich, dass GCC das% esp in old_stack_ptr speicherte, aber% esp nicht durch new_stack_ptr ersetzte. Bei tiefer Inspektion, fand ich es erweiterte eigentlich meinen Montag und seine eigene Anweisungen gegeben, die die folgenden:

mov -0x14(%ebp),%eax 
mov %esp,%eax 
mov %eax,%esp 
mov %eax,-0x18(%ebp) 

denke ich GCC das% esp zu bewahren versucht, weil ich es nicht explizit deklariert als ein "Ausgabe" -Operand ... Ich könnte total falsch damit sein ...

Ich wollte wirklich erweiterte Inline-Assembly, um dies zu tun, denn wenn nicht, es scheint, als ob ich den Ort "hart codieren" muss Offsets von% ebp in die Assembly, und ich würde lieber die Variablennamen so verwenden ... vor allem, weil dieser Code auf einigen verschiedenen Systemen funktionieren muss, die alle meine Variablen auf unterschiedliche Weise zu kompensieren scheinen, also die erweiterte Inline-Assemblierung verwenden erlaubt mir das explizit zu machen Ich sage die Variable location ... aber ich verstehe nicht, warum es die zusätzlichen Sachen macht und ich darf den Stack-Pointer nicht überschreiben, wie es vorher war, seit ich angefangen habe, Extended Assembly zu verwenden, macht es das.

Ich schätze jede Hilfe !!!

+0

Nicht sicher, ob das hilft, aber vielleicht würde '-Fomit-frame-pointer' (das mit' -O1' und höher aktiviert ist) die Notwendigkeit beseitigen, sich um '% ebp' zu kümmern. – DaoWen

+0

Das zusätzliche Zeug ist wahrscheinlich da, weil Sie eine Debug (keine Optimierung) Build und GCC tut es standardmäßig, um potenzielle Fehler zu fangen. Suchen Sie nach "GCC Stack Frame Checks", um zu sehen, welche Optionen GCC bietet. – Skizz

Antwort

8

Okay, das Problem ist gcc ist die Zuordnung von Eingabe und Ausgabe zum gleichen Register eax. Sie möchten gcc sagen, dass Sie die Ausgabe überladen, bevor Sie die Eingabe verwenden, aka. "Frühkrümel".

asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=&r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

Beachten Sie die & Zeichen für die Ausgabe. Dies sollte Ihren Code beheben.

aktualisieren: Alternativ können Sie Ein- und Ausgangs zwingen, das gleiche Register zu sein und xchg zu verwenden, etwa so:

asm __volatile__("xchg %%esp, %0\n\t" 
     : "=r"(old_stack_ptr) /* output */ 
     : "0"(new_stack_ptr) /* input */ 
     ); 

Beachten Sie die "0", die "setzen diese in das gleiche Register wie Argument sagt 0 ".

+0

Vielen Dank soooo! Ich habe noch nie von früherem Klamauk gehört. Ausgezeichnete Antwort. Ich schätze es sehr. Das hat es behoben. – Chad

+1

Ich nehme an, alternativ könnten Sie einfach 'xchg' verwenden und dann erzwingen, dass Eingabe und Ausgabe im selben Register sind. – Jester