I'm working on a JIT compiler, and trying to figure out how to output proper cleanup blocks for managed types such as strings.
The disassembly of the cleanup block for a function that has one local variable of type string
looks like this:
0044333C 648910 mov fs:[eax],edx
0044333F 6854334400 push $00443354
00443344 8D45FC lea eax,[ebp-$04]
00443347 E81834FCFF call @UStrClr
0044334C C3 ret
0044334D E9062BFCFF jmp @HandleFinally
00443352 EBF0 jmp $00443344
Unfortunately, I don't have any good way to obtain the addresses of @UStrClr
and @HandleFinally
so my JITter can insert them. They're declared in System.Pas as _UStrClr
and _HandleFinally
, in the interface section, but apparently there's some "magic" going on because trying to use those identifiers results in a compiler error.
So I tried an ASM routine, where I declared a global pointer and said mov func_ustr_clear, @UStrClear
. This time I don't get an undeclared identifier error; I get something even stranger:
[DCC Error]: E2107 Operand size mismatch
So does anyone have any idea how to do this right?
Try these functions to get the address of UStrClr
and HandleFinally
:
function GetUStrClrAddress: Pointer;
asm
{$IFDEF CPUX64}
mov rcx, offset System.@UStrClr;
mov @Result, rcx;
{$ELSE}
mov @Result, offset System.@UStrClr;
{$ENDIF}
end;
function GetHandleFinallyAddress: Pointer;
asm
{$IFDEF CPUX64}
mov rcx, offset System.@HandleFinally;
mov @Result, rcx;
{$ELSE}
mov @Result, offset System.@HandleFinally;
{$ENDIF}
end;
Edit:
@ArnaudBouchez also suggests some further optimization. By directly putting the value into the function return register, the function is a little faster.
function GetUStrClrAddress: Pointer;
asm
{$ifdef CPU64}
mov rax,offset System.@UStrClr
{$else}
mov eax,offset System.@UStrClr
{$endif}
end;
Further reading of the assembler use in Delphi could be found here (and the use of the OFFSET
keyword), Assembly Expressions, Expression Classes
.