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

1

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?

Cyclostome answered 20/1, 2014 at 3:26 Comment(2)
Maybe calling Finalize is an option?Nudd
If you have madExcept, its source code is a treasure trove for such techniquesRepulsive
W
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.

Warner answered 20/1, 2014 at 6:28 Comment(6)
@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. +1Wishbone
Alternative shorter/cleaner code: function GetUStrClrAddress: Pointer; asm {$ifdef CPU64} mov rax,offset System.@UStrClr {$else} mov eax,offset System.@UStrClr {$endif} end;Wishbone
Aha! The Offset keyword was what I was missing. Thanks!Cyclostome
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).Orthogenic
@PhiS, sorry I have no experience about using PIC OS'es, like OSX or linux.Warner
@Orthogenic PIC code would look like this, I think: MOV EAX,[EBX].OFFSET System.@UStrClr Repulsive

© 2022 - 2024 — McMap. All rights reserved.