Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi label and asm weirdness?

I written an asm function in Delphi 7 but it transforms my code to something else:

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;

Why does it generate push ebx and pop ebx? And why does it do mov eax, ebx?

It seems that it generates the partial stack frame because of the mov eax, ebx.

This simple test generates mov eax, edx but doesn't generate that stack frame:

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

It seems that it has something to do with the label err. If I remove that I don't get the mov eax, * part.

Why does this happen?


Made a bug report on Quality Central.

like image 510
Egon Avatar asked Mar 07 '10 09:03

Egon


2 Answers

The practical advice is: do not use label keyword in asm code, use @@-prefixed labels:

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;

Updated:

I have not found the bug report in Basm area. It looks like a bug, but I have used BASM for many years and never thought about using label keyword such a way. In fact I never used label keyword in Delphi at all. :)

like image 116
kludg Avatar answered Sep 28 '22 12:09

kludg


Well ... back then, in the Delphi-Manual, it used to say something about Compiler-Optimization and thealike-crazyness:


The Compiler generates Stackframes only for nested Routines, for Routines having local Variables and for Routines with Stack-Parameters

The auto-generated Initialization- and Finalizationcode for Routines includes:

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

If local Variables contain Variants, long Strings or Interfaces they are initialized with Null but aren't finalized afterwards.

Locals is the Size of local Variables, Params the Size of Parameters. If both Locals as well as Params are Null no Init-Code will be generated and the Finalizationcode only contains a RET-Intruction.


Maybe that has got something to do with it all...

like image 20
e01f Avatar answered Sep 28 '22 11:09

e01f