2014-01-20 81 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

啊哈! 「偏移量」關鍵字是我錯過的。謝謝! –