Delphi-Label und asm Seltsamkeit?
Frage
ich eine asm-Funktion in Delphi 7 geschrieben, aber es verwandelt sich der Code etwas anderes:
function f(x: Cardinal): Cardinal; register;
label err;
asm
not eax
mov edx,eax
shr edx, 1
and eax, edx
bsf ecx, eax
jz err
mov eax, 1
shl eax, cl
mov edx, eax
add edx, edx
or eax, edx
ret
err:
xor eax, eax
end;
// compiled version
f:
push ebx // !!!
not eax
mov edx,eax
shr edx, 1
and eax, edx
bsf ecx, eax
jz +$0e
mov eax, 1
shl eax, cl
mov edx, eax
add edx, edx
or eax, edx
ret
err:
xor eax, eax
mov eax, ebx // !!!
pop ebx // !!!
ret
// the almost equivalent without asm
function f(x: Cardinal): Cardinal;
var
c: Cardinal;
begin
x := not x;
x := x and x shr 1;
if x <> 0 then
begin
c := bsf(x); // bitscanforward
x := 1 shl c;
Result := x or (x shl 1)
end
else
Result := 0;
end;
Warum generiert es push ebx
und pop ebx
? Und warum tut sie mov eax, ebx
?
Es scheint, dass es den Teilstapelrahmen erzeugt wegen der mov eax, ebx
.
Dieser einfache Test erzeugt mov eax, edx
erzeugt aber keine dieser Stapelrahmen:
function asmtest(x: Cardinal): Cardinal; register;
label err;
asm
not eax
and eax, 1
jz err
ret
err:
xor eax, eax
end;
// compiled
asmtest:
not eax
and eax, $01
jz +$01
ret
xor eax, eax
mov eax, edx // !!!
ret
Es scheint, dass es etwas mit dem label err
zu tun hat. Wenn ich entfernen, dass ich nicht die mov eax, *
Teil bekommt.
Warum ist das passiert?
Made einen Fehlerbericht auf Quality Central .
Lösung
Der praktische Rat: Verwenden Sie keine Etiketten Schlüsselwort nicht in asm-Code, Verwendung @@ - Präfix Etikett:
function f(x: Cardinal): Cardinal; register;
asm
not eax
mov edx,eax
shr edx, 1
and eax, edx
bsf ecx, eax
jz @@err
mov eax, 1
shl eax, cl
mov edx, eax
add edx, edx
or eax, edx
ret
@@err:
xor eax, eax
end;
Aktualisiert :
Ich habe nicht den Fehlerbericht in Basm Bereich . Es sieht aus wie ein Fehler, aber ich habe BASM seit vielen Jahren verwendet und nie daran gedacht Etikett mit Keyword eine solche Art und Weise. In der Tat ich Etikett Stichwort überhaupt nicht in Delphi verwendet. :)
Andere Tipps
Nun ... damals in der Delphi-Handbuch, verwendet es etwas über Compiler-Optimierung zu sagen und thealike-Verrücktheit:
Der Compiler erzeugt Stackframes nur für verschachtelte Routinen, für Routinen lokale Variablen mit und für Routinen mit Stapel-Parametern
Die automatisch generierte Initialization- und Finalizationcode für Routinen enthalten:
PUSH EBP ; If Locals <> 0 or Params <> 0
MOV EBP,ESP ; If Locals <> 0 or Params <> 0
SUB ESP,Locals ; If Locals <> 0
...
MOV ESP,EBP ; If Locals <> 0
POP EBP ; If Locals <> 0 or Params <> 0
RET Params ; Always
Wenn lokale Variablen Varianten enthalten, lange Strings oder Interfaces sie mit Null initialisiert werden, sind aber danach nicht abgeschlossen.
Die Einheimischen ist die Größe der lokalen Variablen, Params die Größe der Parameter. Wenn sowohl Einheimische als auch Params ist Null kein Init-Kodex wird generiert und der Finalizationcode enthält nur eine RET-Intruction.
Vielleicht hat, dass hat etwas damit zu tun alle ...