Delphi etiqueta y rarezas asm?
Pregunta
he escrito una función asm en Delphi 7, pero se transforma mi código a otra cosa:
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;
¿Por qué se genera push ebx
y pop ebx
? Y por qué es lo que hace mov eax, ebx
?
Parece que genera el marco de pila parcial debido a la mov eax, ebx
.
Esta sencilla prueba genera mov eax, edx
pero no genera ese marco de pila:
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
Parece que tiene algo que ver con la label err
. Si quito que no entiendo la parte mov eax, *
.
¿Por qué sucede esto?
Hecho un informe de error en Quality Central .
Solución
El consejo práctico es: no utilizar palabras clave de etiquetas en código ensamblador, uso @@ - prefijo etiquetas:
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;
Actualización
No he encontrado el informe de error en Basm área . Se ve como un insecto, pero he utilizado BASM durante muchos años y nunca pensado en utilizar Etiqueta de palabra clave de tal manera. De hecho nunca he usado la palabra clave etiqueta en Delphi en absoluto. :)
Otros consejos
Bueno ... en ese entonces, en el Delphi-Manual, se utiliza para decir algo sobre Compilador-Optimización y thealike-locura:
El compilador genera Stackframes sólo para rutinas anidadas, para las rutinas que tiene variables locales y para las rutinas con Stack-Parámetros
El Initialization- generada automáticamente y Finalizationcode para las rutinas incluye:
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
Si las variables locales contienen variantes, largas cadenas o interfaces que se inicializan con Null, pero no se han finalizado después.
Los locales es el tamaño de las variables locales, Parámetros del tamaño de los parámetros. Si ambos locales, así como Parámetros son nulos sin Init-código será generado y el Finalizationcode sólo contiene un RET-Intruction.
Tal vez eso tiene algo que ver con todo ...