2010-03-07 12 views
5

he escrito una función asm en Delphi 7, pero se transforma mi código a otra cosa:Etiqueta Delphi y rareza asm?

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é lo hace mov eax, ebx?

Parece que genera el marco de pila parcial debido al 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 elimino eso, no obtengo la parte mov eax, *.

¿Por qué sucede esto?


Hicimos un informe de error en Quality Central.

+0

favor repórtelo como un error en http://qc.embarcadero.com/wc/qcmain.aspx –

+0

@Jeroen seguro. . no hay problema ... – Egon

+0

Ha hecho varias preguntas "por qué" aquí, pero ninguna de ellas fue respondida por la respuesta que usted aceptó. Parece que realmente solo quería saber cómo pasar a una nueva instrucción en ensamblador Delphi sin tener en cuenta por qué sus propios intentos fallaron. Es eso exacto? –

Respuesta

7

El consejo práctico es: no utilizar palabras clave de etiquetas en código ensamblador, utilice @@ - etiquetas prefijadas:

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; 

Actualizado:

no he encontrado el informe de error en Basm area. Parece un error, pero he usado BASM durante muchos años y nunca pensé en usar la palabra clave label de esa manera. De hecho, nunca utilicé palabra clave de etiqueta en Delphi en absoluto. :)

+0

Guau, eso lo arregla ... –

+0

Cualquier idea por qué 'etiqueta' genera ese' mov eax, * 'cosa ... ¿Es un error? ¿O solo un comportamiento extraño? – Egon

+0

En lugar de @@ MyLabel, también @MyLabel (con una sola "@") está bien en bloques de asm..end. – PhiS

1

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, por rutinas que tienen las variables locales y para las rutinas con Stack-Parámetros

La auto-generado Initialization- 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, cadenas largas o interfaces, se inicializan con nulo pero no se finalizan después.

Locales es el tamaño de las variables locales, parámetros del tamaño de los parámetros. Si tanto los locales como los parámetros son nulos, no se generará el código de inicio y el código de finalización solo contiene una instrucción RET.


Tal vez eso tiene algo que ver con todo ...