6

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?

PhiS
  • 4,540
  • 25
  • 35
Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477

1 Answers1

8

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.

LU RD
  • 34,438
  • 5
  • 88
  • 296
  • `@Result` could be replaced by `Result` here AFAIK. Or directly the result register, but the Delphi asm will do it for you so `Result` is just fine here. +1 – Arnaud Bouchez Jan 20 '14 at 06:50
  • 1
    Alternative shorter/cleaner code: `function GetUStrClrAddress: Pointer; asm {$ifdef CPU64} mov rax,offset System.@UStrClr {$else} mov eax,offset System.@UStrClr {$endif} end;` – Arnaud Bouchez Jan 20 '14 at 07:09
  • Aha! The `Offset` keyword was what I was missing. Thanks! – Mason Wheeler Jan 20 '14 at 07:14
  • I am wondering: would that still be sufficient for 32-bit Position Independent Code (PIC) also, or would you have to add the GOT address (usu. in EBX) -- this is obviously not an issue for Win32 (and I don't know if the OP cares for other OSes). – PhiS Jan 20 '14 at 08:40
  • @PhiS, sorry I have no experience about using PIC OS'es, like OSX or linux. – LU RD Jan 20 '14 at 08:54
  • 1
    @PhiS PIC code would look like this, I think: `MOV EAX,[EBX].OFFSET System.@UStrClr ` – David Heffernan Jan 20 '14 at 13:15