2013-04-20 19 views
12

Ich verstehe, dass ich das Link-Register zu Beginn eines Funktionsaufrufs drücken muss, und diesen Wert vor dem Zurückgeben an den Programmcouter abrufen, damit die Ausführung einen von wo vor dem Funktionsaufruf ausführen kann.ARM: Warum muss ich bei Funktionsaufrufen zwei Register drücken/öffnen?

Was ich nicht verstehe ist, warum die meisten Leute dies tun, indem sie dem Push/Pop ein zusätzliches Register hinzufügen. Zum Beispiel:

push {ip, lr} 
... 
pop {ip, pc} 

Zum Beispiel, hier ist eine Hallo Welt in ARM, zur Verfügung gestellt von der official ARM blog:

.syntax unified 

    @ -------------------------------- 
    .global main 
main: 
    @ Stack the return address (lr) in addition to a dummy register (ip) to 
    @ keep the stack 8-byte aligned. 
    push {ip, lr} 

    @ Load the argument and perform the call. This is like 'printf("...")' in C. 
    ldr  r0, =message 
    bl  printf 

    @ Exit from 'main'. This is like 'return 0' in C. 
    mov  r0, #0  @ Return 0. 
    @ Pop the dummy ip to reverse our alignment fix, and pop the original lr 
    @ value directly into pc — the Program Counter — to return. 
    pop  {ip, pc} 

    @ -------------------------------- 
    @ Data for the printf calls. The GNU assembler's ".asciz" directive 
    @ automatically adds a NULL character termination. 
message: 
    .asciz "Hello, world.\n" 

Frage 1: Was ist der Grund für das "Dummy-Register" ist, wie sie es nennen ? Warum nicht einfach {lr} und Pop {pc} drücken? Sie sagen, es ist der Stapel 8-Byte ausgerichtet zu halten, aber ist nicht der Stapel 4-Byte ausgerichtet?

Frage 2: Welche Register ist "ip" (das heißt, r7 oder was?)

+0

Ich bin mit einem ARM-Blog-Post verbunden, wo sie dieses Zwei-Register-Muster empfehlen. Bitte schau es dir an, dort ist ein Code. –

+0

Verwendung von Links wird auf SO abgeraten, weil der Link nicht so lange dauern wie die Frage (und/oder sie einfach die Frage entfernen, weil sie Links verwendet, anstatt die Diskussion hier zu haben). –

+0

Ahh, also der Link beantwortet Ihre Frage. Sie dürfen diese Antwort selbst veröffentlichen. und schließe diese Frage aus. –

Antwort

5

, was der Grund für das "Dummy-Register" ist, wie sie es nennen? Warum nicht einfach {lr} und Pop {pc} drücken? Sie sagen, es ist der Stapel 8-Byte ausgerichtet zu halten, aber ist nicht der Stapel 4-Byte ausgerichtet?

Der Stapel erfordert nur 4-Byte-Ausrichtung; aber wenn der Datenbus 64 Bits breit ist (wie es auf vielen modernen ARMs ist), ist es effizienter, es bei einer 8-Byte-Ausrichtung zu halten. Wenn Sie beispielsweise eine Funktion aufrufen, die benötigt, um zwei Register zu stapeln, kann dies in einem einzelnen 64-Bit-Schreibvorgang anstelle von zwei 32-Bit-Schreibvorgängen erfolgen.

UPDATE: Offenbar ist es nicht nur für die Effizienz; es ist eine Anforderung des offiziellen Prozeduraufrufstandards, wie in den Anmerkungen bemerkt.

Wenn Sie auf ältere 32-Bit-ARMs abzielen, kann das zusätzliche gestapelte Register die Leistung leicht beeinträchtigen.

welche Register ist "ip" (das heißt, R 7, oder was?)

r12. Siehe z. B. here für den vollständigen Satz von Registeraliasen, die vom Prozeduraufrufstandard verwendet werden.

+0

Vielen Dank, das erklärt es. –

+1

Diese Antwort ist irreführend und gefährlich. Die 8-Byte-Ausrichtung ist eine Voraussetzung für den gesamten EABI-konformen Code. Wenn sie nicht an allen externen Grenzen verwaltet wird, kann dies zu Laufzeitfehlern führen. Außerdem kann sie zu Laufzeitfehlern führen, wenn sie auf bestimmten Versionen von Compilern auf bestimmten Prozessoren ausgeführt wird. – unixsmurf

+2

Nur echo @ unixsmurf Antwort. 5.2.1.2 des AAPCS gibt "SP mod 8 = 0 an. Der Stapel muss doppelt ausgerichtet sein." für öffentliche Schnittstellen. Du willst das wirklich immer tun, wenn du nicht weißt, was du tust. ARM verfügt über einen Wissensartikel zur [8-Byte-Stapelausrichtung] (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html). – jszakmeister

3

Da Sie sie speichern und wiederherstellen möchten, nachdem Sie Ihre Funktion ausführen. Auf der Funktion entren speichert es die ip und lr Register (mit dem Namen prolog). Nachdem die Funktion Finishing es ordnet beide (epilog):

pc <- lr 

ip <- old_ip 

EDIT

Register r12 wird auch als IP bezeichnet und wird als inner Procedure Call Scratch-Register verwendet werden, siehe also.

Die Konvention ist, dass der Angerufene Funktion ip,r0-r3 ändern können, so müssen Sie diese wiederherstellen, auf dem calling convention

EDIT2 dependes: Why we might want the stack to be 8 aligned on ARM

Wenn der Stapel nicht Acht-Byte ist die Verwendung ausgerichtet von LDRD und STRD (load and store doubleword) könnte verursachen einen Ausrichtungsfehler, je nach Ziel und Konfiguration verwendet.

Hinweis that we have the same issue on X86 und auf Mac OS we have 16 bytes alignment

+0

Ich weiß, dass es das tut.Meine Frage ist, warum die meisten Leute zwei Register bei Push/Pop verwenden. Warum nicht {lr} und pop {pc} einfach drücken? –

+0

Da die Sprache Sie {Liste der Register} drücken können, und ist eine Assembly-Anweisung, vorausgesetzt, Sie möchten speichern "r0-r15" Sie können es in 32-Bit-Codelänge oder 15 * 32bit Codelänge, was ist besser? http://en.wikipedia.org/wiki/KISS_principle – 0x90

+0

Sie haben meine Frage nicht verstanden. Ich habe es überarbeitet, überprüfe es. –

6

8-Byte-Ausrichtung ist eine Voraussetzung für die Interoperabilität zwischen Objekten, die AAPCS entsprechen.

ARM hat eine beratende Anmerkung zu diesem Thema:

ABI for the ARM® Architecture Advisory Note – SP must be 8-byte aligned on entry to AAPCS-conforming functions

Artikel zwei Gründe erwähnen 8-Byte-Ausrichtung

  • Ausrichtung Fehler oder unvorhersehbares Verhalten zu verwenden. (Gründe für Hardware/Architektur - LDRD/STRD könnte einen Ausrichtungsfehler verursachen oder ein UNPRÄZISIONSBARES Verhalten auf anderen Architekturen als ARMv7 zeigen)

  • Anwendungsfehler. (Compiler - Runtime Annahme Unterschiede geben sie va_start und va_arg als Beispiel)

Natürlich ist dies alles über öffentliche Schnittstellen, wenn Sie eine statische ausführbare ohne zusätzliche machen Verknüpfung Sie Stapel auf 4 Byte ausrichten .

+0

Erwähnenswert: die Speicher 2 Register Use Case ist so üblich, dass in Armv8, die "Push" und "Pop" fallen gelassen hat, dedizierte Push-Paar und Pop-Paar-Anweisungen "stp" und "ldp": http: // stackoverflow. com/fragen/27941220/push-lr-und-pop-lr-in-arm-arch64 –

Verwandte Themen