我正在研究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
所以有人知道如何做到这一点吗?
答案 0 :(得分:8)
尝试使用这些函数获取UStrClr
和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;
编辑:
@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
。