gibt es drei Fälle, in denen Sie Sollte sich bewusst sein.
- Blatt:
void foo(void) {};
- Endaufruf:
int foo(void) { return bar(); };
- Intermediate:
int foo(void) { int i; i = bar() + 4; return i; };
Es gibt viele Möglichkeiten, diese Anrufe zu implementieren. Im Folgenden sind einige Beispiele und sind nicht die einzige Möglichkeit, Epilog und Prolog in ARM-Assembler zu implementieren.
LEAF funtions
Viele Funktionen sind die Blatt Typ und erfordern keine Speicherung der lr
. Sie verwenden einfach die bx lr
, um zurückzukehren. Zum Beispiel
SubRoutine:
PUSH {r1,r2}
//code that changes r1 and r2
POP {r1,r2}
bx lr
Auch ist es typisch, dass R1 und R2 verwendet Parameter zu übergeben und eine Unterroutine ist frei, sie zu nutzen/zerstören. ARM calling conventions Dies ist der Fall, wenn Sie die C-Funktion von Assembler aufrufen. So würde normalerweise niemand r1 und r2 speichern, aber da es Assembler ist, können Sie tun, was immer Sie wollen (auch wenn es eine schlechte Idee ist). Also das Beispiel ist eigentlich nur bx lr
, wenn Sie dem Standard folgen.
Endaufruf
Wenn Ihre Funktion ein Blatt ist mit Ausnahme einer letzten Aufruf einer anderen Funktion Sie folgende Abkürzung verwenden können,
Sub_w_tail:
// Save callee-saved regs (for whatever calling convention you need)
// Leave LR as is.
// ... do stuff
B tail_call
Die LR
wird gespeichert durch den Anrufer zu Sub_w_tail
und Sie springen einfach direkt zu tail_call
, die an den ursprünglichen Anrufer zurückkehrt.
Intermediate Funktion
Dies ist der komplexeste. Hier ist eine mögliche Folge,
SubRoutine:
PUSH {r1,r2,lr}
//code that changes r1 and r2
bl AnotherRoutine (where bx lr will be used to return from it)
// more code
POP {r1,r2,pc} // returns to caller of 'SubRoutine'
Einige Details einer älteren Aufrufkonvention sind in der ARM Link and frame registers Frage. Sie können diese Konvention verwenden. Es gibt viele verschiedene Möglichkeiten, um den Epilog und Prolog in ARM-Assembler durchzuführen.
Der letzte ist ziemlich komplex; oder zumindest mühsam zu programmieren. Es ist viel besser, einen Compiler bestimmen zu lassen, welche Register zu verwenden sind und was auf den Stack zu legen ist. In der Regel müssen Sie jedoch nur wissen, wie die erste (LEAF-Funktion) geschrieben wird, wenn Sie Assembler schreiben. Es ist am produktivsten, nur eine optimierte Unterroutine zu programmieren, die von einer höheren Programmiersprache in Assembler aufgerufen wird. Es ist nützlich zu wissen, wie alle von ihnen arbeiten, um kompilierten Code zu verstehen. Sie sollten auch Inline Assembler in Erwägung ziehen, damit Sie sich nicht mit diesen Nuancen befassen müssen.
Wenn Sie sich die Mühe gemacht hätten, das Handbuch zu lesen, würden Sie wissen, dass 'pop' mit' pc' in der Liste ein Interworking-Zweig seit ARMv5T ist. Die 'bxlr' nach ihr wird nie erreicht. – EOF
"Ich weiß nicht, warum du den PC POPSTEN würdest, wenn du den LR gedrängt hast." ---- hört sich so an, als ob dir hier etwas Grundlegendes fehlt. Sie drücken einen Wert __ aus dem LR__ und dann setzen Sie diesen Wert __in den PC__ (und führen Sie so die Verzweigung zu dieser Adresse). Sie müssen einige Grundlagen auf asm Programmierung lesen, es gibt viele Sachen im Netz ... –
gut das ist, was ich über Klärung für – SeesSound