Pergunta

Escrevi um asm função em Delphi 7, mas transforma o meu código para outra coisa:

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 que não gerar push ebx e pop ebx?E por que ele faz mov eax, ebx?

Parece que ele gera parcial do quadro de pilha devido a mov eax, ebx.

Este teste simples gera mov eax, edx mas não gerar o quadro de pilha:

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 ele tem algo a ver com o label err.Se eu remover o que não tenho mov eax, * a parte.

Por que isso acontece?


Fez um relatório de bug no Qualidade Central.

Foi útil?

Solução

O conselho prático é: não use a palavra-chave do rótulo no código ASM, use @@-etiquetas prefixadas:

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;

Atualizada:

Eu não encontrei o relatório de bug em Área BASM. Parece um bug, mas eu uso o BASM há muitos anos e nunca pensei em usar a palavra -chave do rótulo dessa maneira. Na verdade, eu nunca usei a palavra -chave do rótulo em Delphi. :)

Outras dicas

Bem ...de volta, em seguida, em Delphi-Manual, usado para dizer algo sobre o Compilador de Otimização e thealike-loucura:


O Compilador gera Stackframes apenas para outras Rotinas, por Rotinas de ter Variáveis locais e Rotinas com Pilha-Parâmetros

O auto-gerado de Inicialização e Finalizationcode para Rotinas inclui:

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 as Variáveis locais conter Variantes, Cadeias longas ou Interfaces que são inicializados com um valor Nulo, mas não são registrados posteriormente.

Moradores é o Tamanho de Variáveis locais, Parâmetros o Tamanho de Parâmetros.Se ambos os Locais, bem como de Parâmetros são Nulos não Init-Código será gerado e o Finalizationcode contém apenas um RET-Intruction.


Talvez que tem algo a ver com tudo isso...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top