Delphi标签和asm怪异?

Ego*_*gon 5 delphi x86 assembly delphi-7 basm

我在Delphi 7中编写了一个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;
Run Code Online (Sandbox Code Playgroud)

它为什么生成push ebxpop ebx?它为什么这样做mov eax, ebx

它似乎因为它而生成部分堆栈帧mov eax, ebx.

这个简单的测试生成mov eax, edx但不生成该堆栈帧:

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
Run Code Online (Sandbox Code Playgroud)

它似乎与它有关label err.如果我删除,我没有得到的mov eax, *部分.

为什么会这样?


制作了有关Quality Central的错误报告.

klu*_*udg 7

实用建议是:不要在asm代码中使用label关键字,使用@@ - 前缀标签:

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;
Run Code Online (Sandbox Code Playgroud)

更新:

我还没有在Basm区找到bug报告.它看起来像一个bug,但我已经使用BASM很多年了,从来没有想过使用label关键字这样的方式.实际上我从来没有在Delphi中使用label关键字.:)