2016-06-01 8 views
2

I habe manchmal festgestellt, dass, wenn I-C-Code des Assembler-Code zu kompilieren manchmal in Methode 1 erzeugt wird:die Funktion des Prelog und Epilog in Arm gcc Controlling

STR R11, [SP, #-4]! 
ADD R11, SP, #0 
SUB SP, SP, #4 

und manchmal in Methode 2:

STMFD SP!, {R11, LR} 
ADD R11, SP, #4 
SUB SP, SP, #4 

Der Unterschied zwischen der ersten und der zweiten Methode besteht darin, dass die zweite Methode LR in den Stack speichert.

Im Moment stehe ich vor einem Problem, wo meine Funktion, die wie die erste Methode startet, eine andere Funktion über das Linkregister (BL) aufruft, und da meine Funktion das LR nicht zuerst speichert, verursacht das ein ernstes Problem Problem. Wenn ich dem Compiler sagen könnte, die zweite Methode zu verwenden, könnte es mein Problem lösen.

Es kann mit der Tatsache verbunden sein, dass die Funktion die innere Funktion aufruft, die Inline-Assembly verwendet und daher "nicht erkennt", dass ein Aufruf an eine andere Funktion ist und keinen Sinn beim Speichern des LR sieht. Der Aufruf der Inline-Assembly ist obligatorisch, da die aufgerufene Funktion den Wert von SP als Parameter erhält.

Dies ist eine ziemlich catch-22-Situation, hoffentlich könnte mir jemand helfen, das zu lösen. Danke!

+0

Warum Sie die Frage "C" Tag haben, ohne gezeigt zu haben, wie Sie Ihre Funktion in C aussieht? – user3078414

+2

Es könnte eine gute Idee sein, den Aufruf in der Inline-Assembly durch einen Aufruf in C zu ersetzen. – fuz

+0

Wenn Sie eine Assembly benötigen, um SP zu erhalten, verwenden Sie sie, um SP zu erhalten; der Aufruf ist nicht verwandt, also tu es in C. Das sollte nicht schwer sein, aber du zeigst deinen Code nicht, damit wir es nicht wissen können. – ElderBug

Antwort

1

Mark lr als clobbered den Compiler speichern zu machen:

extern void foo(void); 
extern void bar(void) 
{ 
    asm ("bl foo" : : : "lr"); 
} 

erzeugt den folgenden Code:

bar: 
    str lr, [sp, #-4]! 
    bl foo 
    ldr lr, [sp], #4 
    bx lr 

the documentation Details für mehr sehen. Denken Sie daran, alle anderen Register, die Sie verwenden, auch als verpatzt zu markieren. Andernfalls könnte der Compiler eine Variable in eine von ihnen einfügen. Eventuell müssen Sie auch alle Register, die vom Anrufer gespeichert wurden, als verrauscht markieren.

+0

Danke :) ___ – YouYou

+0

@YouYou Es ist mir ein Vergnügen. – fuz

0

Es gibt mehrere Lösungen, um LR zu speichern.

1) Sie können es manuell speichern, da Sie Inline-Assembly schreiben, können Sie LR vor dem Aufruf Ihrer Funktion speichern und nach dem Aufruf wiederherstellen.

2) Sie können eine Dummy-Variable deklarieren, die mit dem folgenden C-Code in LR gestellt werden:

register int foo asm ("lr"); 

3) Verwenden Sie clobbers in your inline assembly

Beachten Sie, dass die beste Lösung ist wahrscheinlich die dritte.

1

Die einfachste/direkte Antwort ist, lr zum Clobber hinzuzufügen, aber Sie müssen möglicherweise mehr hinzufügen!


WARUM ??

Compiler generieren je nach Art der Funktion unterschiedliche Prolog/Epilog. Sie können eine generische Funktion, eine Blattfunktion (ruft keine anderen) oder eine Tail Call sein. Sie haben keinen Code angezeigt, daher ist es schwierig, Ihre speziellen Umstände zu kennen.Wenn Sie jedoch nicht dokumentieren, dass Ihr Inline-Assembler eine andere Funktion aufruft, dann denkt gcc, dass es eine Blatt--Funktion ist, wenn dies nicht der Fall ist.

Vom gcc assembler documentation,

Zugriff auf Daten von C-Programmen ohne Eingabe/Ausgabe-Operanden (zB durch globale Symbole direkt von der Assembler-Vorlage) nicht wie erwartet funktionieren. In ähnlicher Weise erfordert das direkte Aufrufen von Funktionen aus einer Assembler-Vorlage ein detailliertes Verständnis des Ziel-Assemblers und ABI.

Aus diesem Grund denke ich, dass es am sichersten ist r0 hinzuzufügen - auch r3 und lr den clobbers. Möglicherweise ist auch ein Neon-/Gleitkommaregister erforderlich. Der Compiler sollte darauf hingewiesen werden, dass diese die Inline-Anweisung asm ändern können.

Sie können einen Tail-Aufruf verwenden, wenn nach der Assembler-Anweisung kein Code vorhanden ist und Sie davon ausgehen, dass kein 'frame pointer' oder andere Register verwendet werden. Dh, ersetze bl inline_asm_target durch nur b inline_asm_target, wobei die Funktion inline_asm_target immer noch eine bx lr (oder was immer für die Compiler-Optionen/ABI in Verwendung ist) tut.

Verwandte:
- ARM link register and frame pointer
- ARM to C calling convention registers to save