2010-03-07 9 views
5

I écrit une fonction asm en Delphi 7, mais il transforme mon code à quelque chose d'autre:Étiquette Delphi et asm étrangeté?

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; 

Pourquoi faut-il générer push ebx et pop ebx? Et pourquoi fait-il mov eax, ebx? Il semble qu'il génère la trame de pile partielle en raison de mov eax, ebx.

Ce test simple génère mov eax, edx mais ne génère pas que cadre de pile:

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 

Il semble qu'il a quelque chose à voir avec le label err. Si j'enlève que je n'ai pas la pièce mov eax, *.

Pourquoi cela se produit-il?


Fait un rapport de bogue sur Quality Central.

+0

s'il vous plaît faire un rapport de bug à http://qc.embarcadero.com/wc/qcmain.aspx –

+0

@Jeroen sûr. Aucun problème ... – Egon

+0

Vous avez demandé plusieurs "pourquoi" ici, mais aucune d'entre elles n'a été répondue par la réponse que vous avez acceptée. Il semble que vous vouliez simplement savoir comment sauter à une nouvelle instruction dans l'assembleur Delphi sans tenir compte de la raison pour laquelle vos propres tentatives ont échoué. Est-ce exact? –

Répondre

7

Les conseils pratiques: ne pas utiliser mot-clé étiquette dans le code asm, utilisez @@ - étiquettes préfixés:

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; 

Mis à jour:

Je n'ai pas trouvé le rapport de bogue au Basm area. Cela ressemble à un bug, mais j'ai utilisé BASM pendant de nombreuses années et je n'ai jamais pensé à utiliser un tel mot-clé. En fait, je n'ai jamais utilisé le mot-clé label dans Delphi. :)

+0

Wow, ça résout ... –

+0

Une idée de pourquoi 'label' génère ce' mov eax, * 'thingy ... Est-ce un bug? Ou juste un comportement étrange? – Egon

+0

Au lieu de @@ MyLabel, aussi @MyLabel (avec un seul "@") est bien dans les blocs asm..end. – PhiS

1

Eh bien ... à l'époque, dans le Delphi-Manuel, il l'habitude de dire quelque chose à propos du compilateur-optimisation et thealike-crazyness:


Le compilateur génère Stackframes uniquement pour Routines imbriquées, pour routines ayant des variables locales et des routines de pile Paramètres

Le Initialization- généré automatiquement et Finalizationcode pour routines comprend:

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 les variables locales contiennent des variantes, des chaînes longues ou des interfaces, elles sont initialisées avec Null mais ne sont pas finalisées par la suite. La variable locale est la taille des variables locales, paramètre la taille des paramètres. Si les Locaux aussi bien que les Params sont Nuls, aucun code d'initialisation ne sera généré et le Finalizationcode ne contiendra qu'une RET-Intruction.


Peut-être que cela a quelque chose à voir avec tout cela ...