如何获取内部System.pas函数的地址?

时间:2014-01-20 03:26:40

标签: delphi assembly basm

我正在研究JIT编译器,并试图找出如何为托管类型(如字符串)输出正确的清理块。

对于具有string类型的局部变量的函数,清理块的反汇编如下所示:

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

不幸的是,我没有任何好方法来获取@UStrClr@HandleFinally的地址,因此我的JITter可以插入它们。它们在System.Pas中声明为_UStrClr_HandleFinally,位于接口部分,但显然有一些“魔法”正在进行,因为尝试使用这些标识符会导致编译错误。

所以我尝试了一个ASM例程,在那里我声明了一个全局指针并说mov func_ustr_clear, @UStrClear。这次我没有得到未声明的标识符错误;我得到一些更奇怪的东西:

[DCC Error]: E2107 Operand size mismatch

所以有人知道如何做到这一点吗?

1 个答案:

答案 0 :(得分:8)

尝试使用这些函数获取UStrClrHandleFinally的地址:

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;

编辑:

@ArnaudBouchez也建议进一步优化。通过直接将值放入函数返回寄存器,该函数更快一些。

function GetUStrClrAddress: Pointer; 
asm 
  {$ifdef CPU64} 
    mov rax,offset System.@UStrClr 
  {$else} 
    mov eax,offset System.@UStrClr 
  {$endif} 
end;

可以在此处找到Delphi中汇编程序使用的进一步阅读(以及OFFSET关键字的使用),Assembly Expressions, Expression Classes