Der Code generiert, wenn ich das Kompilieren unter Debug-Einstellungen ist, etwa so:
begin
005A9414 55 push ebp
005A9415 8BEC mov ebp,esp
005A9417 83C4E4 add esp,-$1c
005A941A 33C9 xor ecx,ecx
005A941C 894DEC mov [ebp-$14],ecx
005A941F 894DE8 mov [ebp-$18],ecx
005A9422 894DE4 mov [ebp-$1c],ecx
005A9425 8955F0 mov [ebp-$10],edx
005A9428 8945F4 mov [ebp-$0c],eax
005A942B 33C0 xor eax,eax
005A942D 55 push ebp
005A942E 6890945A00 push $005a9490
005A9433 64FF30 push dword ptr fs:[eax]
005A9436 648920 mov fs:[eax],esp
mov X, eax
005A9439 8945FC mov [ebp-$04],eax
mov Y, edx
005A943C 8955F8 mov [ebp-$08],edx
Wenn der Code ausgeführt wird, wird in der Tat eax
der Zeiger selbst ist. Aber der Compiler hat entschieden, es zu ebp-$0c
zu speichern und dann eax
auf Null zu setzen. Das liegt wirklich am Compiler.
Der Code unter Freigabeeinstellungen ist ziemlich ähnlich. Der Compiler wählt weiterhin eax
. Natürlich können Sie sich nicht darauf verlassen, dass der Compiler das tut. Denken Sie daran,
begin
005A82A4 55 push ebp
005A82A5 8BEC mov ebp,esp
005A82A7 33C9 xor ecx,ecx
005A82A9 51 push ecx
005A82AA 51 push ecx
005A82AB 51 push ecx
005A82AC 51 push ecx
005A82AD 51 push ecx
005A82AE 33C0 xor eax,eax
005A82B0 55 push ebp
005A82B1 6813835A00 push $005a8313
005A82B6 64FF30 push dword ptr fs:[eax]
005A82B9 648920 mov fs:[eax],esp
mov X, eax
005A82BC 8945FC mov [ebp-$04],eax
mov Y, edx
005A82BF 8955F8 mov [ebp-$08],edx
, dass die Parameterübergabe, die den Zustand der Register definiert und stapeln, wenn die Funktion der Ausführung beginnt. Was als nächstes passiert, wie die Funktion die Parameter dekodiert, liegt beim Compiler. Es ist nicht verpflichtet, die Register und den Stack, die für die Parameterübergabe verwendet wurden, unberührt zu lassen. Wenn Sie Asum in die Mitte einer Funktion injizieren, können Sie nicht erwarten, dass die flüchtigen Register wie eax
bestimmte Werte haben. Sie werden halten, was immer der Compiler gerade in sie geschrieben hat.
Wenn Sie die Register am Anfang der Ausführung der Funktion untersuchen möchten, müssen Sie eine reine asm-Funktion verwenden, um sicherzustellen, dass der Compiler die Register ändern zu vermeiden, die für die Parameterübergabe verwendet wurden:
var
X, Y: Pointer;
asm
mov X, eax
mov Y, edx
// .... do something with X and Y
end;
der Compiler wird seine Entscheidungen sehr stark abhängig von dem Code in dem Rest der Funktion machen. Für Ihren Code verursacht die Komplexität des Zusammenfügens der Zeichenfolge, die an übergeben wird, eine ziemlich große Präambel. Betrachten Sie stattdessen diesen Code:
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
i: Integer;
function Sum(j: Integer): Integer;
end;
....
procedure TForm1.FormCreate(Sender: TObject);
begin
i := 624;
Caption := IntToStr(Sum(42));
end;
function TForm1.Sum(j: Integer): Integer;
var
X: Pointer;
begin
asm
mov X, eax
end;
Result := TForm1(X).i + j;
end;
In diesem Fall wird der Code einfach genug für den Compiler eax
allein zu lassen. Der optimierte Release-Build-Code für Sum
ist:
begin
005A8298 55 push ebp
005A8299 8BEC mov ebp,esp
005A829B 51 push ecx
mov X, eax
005A829C 8945FC mov [ebp-$04],eax
Result := TForm4(X).i + j;
005A829F 8B45FC mov eax,[ebp-$04]
005A82A2 8B80A0030000 mov eax,[eax+$000003a0]
005A82A8 03C2 add eax,edx
end;
005A82AA 59 pop ecx
005A82AB 5D pop ebp
005A82AC C3 ret
Und wenn Sie den Code ausführen, wird die Form der Beschriftung auf den erwarteten Wert geändert.
Um ehrlich, Inline-Assembler, als asm-Block in einer Pascal-Funktion gesetzt zu werden, ist nicht sehr nützlich. Die Sache mit dem Schreiben von Assembly ist, dass Sie den Zustand der Register und des Stacks vollständig verstehen müssen. das ist am Anfang und am Ende einer Funktion definiert, die durch die ABI definiert wird.
Aber in der Mitte einer Funktion hängt dieser Zustand vollständig von den Entscheidungen des Compilers ab. Das Eingeben von asm-Blöcken dort erfordert, dass Sie die Entscheidungen kennen, die der Compiler getroffen hat. Es bedeutet auch, dass der Compiler die von Ihnen getroffenen Entscheidungen nicht verstehen kann. Dies ist normalerweise unpraktisch. Tatsächlich verbot Embarcadero für den x64-Compiler solche Inline-asm-Blöcke. Ich persönlich habe nie einen Inline-Asm-Block in meinem Code verwendet. Wenn ich asm schreibe, schreibe ich immer reine asm-Funktionen.
Sie für Ihre sachkundige Kommentare Dank! – SOUser