2014-01-20 36 views
4

我正在研究一个JIT编译器,并试图弄清楚如何为托管类型(如字符串)输出适当的清理块。如何获取System.pas内部函数的地址?

对于具有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

也许调用Finalize是一个选项? – Remko

+0

如果你有madExcept,它的源代码是这种技术的宝库 –

回答

7

尝试这些功能来获得UStrClrHandleFinally地址:

function GetUStrClrAddress: Pointer; 
asm 
{$IFDEF CPUX64} 
    mov rcx, offset [email protected]; 
    mov @Result, rcx; 
{$ELSE} 
    mov @Result, offset [email protected]; 
{$ENDIF} 
end; 

function GetHandleFinallyAddress: Pointer; 
asm 
{$IFDEF CPUX64} 
    mov rcx, offset [email protected]; 
    mov @Result, rcx; 
{$ELSE} 
    mov @Result, offset [email protected]; 
{$ENDIF} 
end; 

编辑:

@ArnaudBouchez也提出了一些进一步的优化。通过直接将该值写入函数返回寄存器,该函数稍微快一点。

function GetUStrClrAddress: Pointer; 
asm 
    {$ifdef CPU64} 
    mov rax,offset [email protected] 
    {$else} 
    mov eax,offset [email protected] 
    {$endif} 
end; 

在Delphi汇编使用的进一步阅读可以在这里找到(和使用OFFSET关键字),Assembly Expressions, Expression Classes

+0

'@ Result'可以被'Result'替换为AFAIK。或直接结果寄存器,但德尔福汇编将为你做,所以'结果'就在这里。 +1 –

+1

其他更短/更清晰的代码:'GetUStrClrAddress:指针; 。 ASM {$ IFDEF CPU64} MOV RAX,偏移系统@ UStrClr {$}其他MOV EAX,偏移系统@ UStrClr {$ ENDIF} 结束;' –

+0

啊哈! “偏移量”关键字是我错过的。谢谢! –