Delphi etichetta e asm stranezza?
Domanda
I scritto una funzione di ASM in Delphi 7, ma si trasforma il mio codice a qualcosa d'altro:
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;
Perché non genera push ebx
e pop ebx
? E perché fa fare mov eax, ebx
?
Sembra che genera lo stack frame parziale causa della mov eax, ebx
.
Questo semplice test genera mov eax, edx
ma non genera che stack frame:
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
Sembra che ha qualcosa a che fare con la label err
. Se rimuovo che non ottengo la parte mov eax, *
.
Perché accade questo?
Ha fatto un bug report su Qualità Centrale .
Soluzione
Il consiglio pratico è: non usare l'etichetta parola chiave nel codice asm, uso @@ - prefisso etichette:
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;
Aggiornamento :
Non ho trovato la segnalazione di bug in Basm zona . Sembra un bug, ma ho usato BASM per molti anni e mai pensato di usare Etichetta parola chiave modo. In realtà non ho mai usato l'etichetta parola chiave a Delfi a tutti. :)
Altri suggerimenti
Beh ... allora, in Delphi-Manual, ha usato per dire qualcosa a proposito del compilatore-Ottimizzazione e thealike-follia:
Il compilatore genera Stackframes solo per routine nidificate, per le routine avere variabili locali e per le routine con Stack-Parameters
L'Initialization- auto-generata e Finalizationcode per le routine comprende:
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
Se le variabili locali contengono varianti, lunghe stringhe o interfacce vengono inizializzati con Null, ma non sono finalizzati in seguito.
La gente del posto è la dimensione delle variabili locali, Params la dimensione dei parametri. Se entrambi i locali così come Parametri sono nulli senza Init-codice verrà generato e l'Finalizationcode contiene solo un RET-Intruction.
Forse questo ha qualcosa a che fare con tutto questo ...