Search code examples
delphiassemblybasm

How can I obtain the address of internal System.pas functions?


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?


Solution

  • 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.