Entfernen von Argumenten aus dem Stapel in i386, ARM-Assembly

8

Ich arbeite mit einigen Trampolin-Funktionen zur Verwendung mit höherer Aufruf in C / Objective-C, eine leichte Wendung auf dem Weg Apple macht es .

Wenn Sie überhaupt mit der Funktionsweise von Objective-C IMP vertraut sind, handelt es sich im Grunde um einen Funktionszeiger, bei dem die ersten beiden Argumente der Empfänger einer Nachricht und der Name des Nachrichtenselektors sind, z. B. void(*)(id obj, SEL sel, ...) . . Neuere Versionen der Laufzeit erlauben es, Methodenimplementierungen zur Laufzeit mit C-Blöcken wie void(^)(id obj, ...) zu synthetisieren. Diese Blöcke haben den Selektor nicht; Die Runtime erstellt ein Trampolin, das den Selektor mit dem Empfänger, den Empfänger mit dem Blockzeiger überschreibt, und fährt dann mit der Ausführung fort.

Ich möchte etwas vage Ähnliches tun, was beinhaltet, dass ich nicht entweder von den ersten beiden Argumenten habe, so dass die Argumente zu diesem Block genau dieselben sind wie die Argumente der traditionellen Methode send plus der Blockzeiger für Ausführungszwecke, dh void(*)(Block *, ...) . Dies erfordert nur das Kopieren in den Blockzeiger, und ich nehme an, ein Argument loszuwerden.

%Vor%

Hier ist die Assembly, die ich auf ARM habe:

%Vor%

Ein ähnlicher Code existiert für den x86_64; Der obige Code stammt somit direkt von Apple. Für persönliches Wissen frage ich mich, wo ich mit dem Ausschneiden eines Arguments beginnen sollte, so dass das erste Argument (was früher der Empfänger war) das Blockliteral, das zweite das erste echte Argument usw. ist.

Ich bin bei ASM unglaublich noobish, also wird jede Hilfe sehr geschätzt. Alles, was ich versucht habe, ist auf immer interessantere Weise in die Luft gegangen. Vielen Dank im Voraus.

    
zwaldowski 02.04.2012, 04:56
quelle

1 Antwort

2

Der iOS-ABI integriert effektiv den AAPCS und definiert nur die Unterschiede, also sollten Sie mit Ссылка zuerst. Dann lesen Sie Apples iOS ABI Function Call Guide (für den Sie eine kostenpflichtige iOS Dev Center-Mitgliedschaft benötigen).

Zusammenfassen der Regeln, Aufruf eines ObjC IMP:

  • Selbst geht in R0
  • _cmd geht in R1
  • erstes int oder Zeigerargument geht in R2
  • zweites int oder Zeigerargument geht in R3
  • alle weiteren Argumente gehen auf den Stapel

Wenn Sie also nur Argumente mit bis zu 2 Parametern betrachten, von denen keiner den Gleitkomma / int64_t / struct enthält, um die Argumente self und _cmd zu entfernen, ist es nur eine Frage des Mischens von R0-R4:

%Vor%

Oder, um eine Funktion zu schreiben, die zwei Parameter benötigt und das self und _cmd einfügt, bevor sie an ein IMP weitergeleitet werden, ist dies genau das:

%Vor%

Im Falle des Blocktrampolins von Apple verwandeln sie einen Anruf in [foo performBlockOnSelf: block] in effektiv [block foo]. Wie Sie sagen, endet der Blockzeiger in r0 (der üblichen Selbstposition) und der Zielparameter foo endet in r1 (die übliche _cmd-Position). Wenn Blöcke wirklich IMPs wären, wäre das natürlich Unsinn, denn foo ist kein SEL, aber sie sind es nicht, also ist es kein Problem.

Aus Ihrer Aussage "Ich möchte etwas vage Ähnliches tun, was beinhaltet, dass ich keines der beiden ersten Argumente habe, so dass die Argumente zu diesem Block genau dieselben sind wie die Argumente der traditionellen Methode:" Ich bin es nicht ganz klar, welche von zwei Dingen du versuchst zu tun:

  1. Definieren Sie ein "Delegate" -Objekt (in C # -Begriffen), im Grunde ein Block mit seinem Ziel, das zur Konstruktionszeit eingebacken ist. In diesem Fall wollen Sie sowohl r0 (den Blockzeiger) als auch r1 (das Ziel) von einer Tabelle von Delegaten nachsehen, anstatt nur den Blockzeiger. Aber du wirst keine Compiler-Hilfe haben, um diese Tabelle einzurichten - was bedeutet, dass du sie einrichten und in reinem C darauf zugreifen kannst, und es wird genauso praktisch sein und ein benutzerdefiniertes Assembly-Trampolin bauen. (Sie könnten es sogar über ObjC-Wörterbücher machen, mit einem Leistungsverlust, der in der Praxis keine Rolle spielt.)

  2. Verwandle eine normale Nachricht in einen Block, in dem alles so gespeichert wird, dass Apples Trampoline-Code, wenn er versucht, den Block aufzurufen, mit der traditionellen Methode send-Parameter anstelle der Block-Parameter endet. Wenn dies Ihr Ziel ist, ist es einfacher und viel sicherer, nur einen Block-Wrapper um die Nachricht zu verwenden, anstatt zu versuchen, die Nachrichten in Blöcke umzuwandeln, und ich bezweifle, dass Effizienz- oder Flexibilitätskosten von Bedeutung sind.

abarnert 08.05.2012, 00:37
quelle

Tags und Links