2009-12-05 39 views
4

背景:如何確保Delphi例程的16字節代碼對齊?

我有一個優化的Delphi/BASM例程單位,主要是用於大量計算。其中一些例程包含內部循環,如果循環開始與DQWORD(16字節)邊界對齊,我可以實現顯着的加速。我可以確保所討論的循環按照需要進行對齊,如果我知道常規入口點處的對齊方式。據我所見,Delphi編譯器將過程/函數與DWORD邊界對齊,例如,給設備添加功能可能會改變後續設備的對齊。但是,只要我將例程的結尾填充爲16的倍數,我可以確保隨後的例程同樣對齊 - 或未對齊,具體取決於第一個例程的對齊方式。因此,我嘗試將關鍵例程放置在單元實現部分的開頭,並在它們之前放置了一些填充代碼,這樣第一個過程就是DQWORD對齊。

這看起來像下面的東西:

interface 

procedure FirstProcInUnit; 

implementation 

procedure __PadFirstProcTo16; 
asm 
    // variable number of NOP instructions here to get the desired code length 
end; 

procedure FirstProcInUnit; 
asm //should start at DQWORD boundary 
    //do something 
    //padding to align the following label to DQWORD boundary 
    @Some16BAlignedLabel: 
     //code, looping back to @Some16BAlignedLabel 
    //do something else 
    ret #params 
    //padding to get code length to multiple of 16 
end; 

initialization 

__PadFirstProcTo16; //call this here so that it isn't optimised out 
ASSERT ((NativeUInt(Pointer(@FirstProcInUnit)) AND $0F) = 0, 'FirstProcInUnit not DQWORD aligned'); 

end. 

這有點脖子一痛,但我可以得到這種在必要時工作的事情。問題是,當我在不同的項目中使用這樣的單元,或者在同一個項目中對其他單元進行一些更改時,這可能仍然會破壞__PadFirstProcTo16本身的對齊。同樣,使用不同的編譯器版本(例如D2009與D2010)重新編譯同一項目也會破壞對齊。所以,我發現做這種事情的唯一方法就是在項目的其餘部分處於最終形式時最後要做的事情。

問題1:

是否有任何其他的方式來實現的保證(至少是某些特定的)程序所需的效果是DQWORD對齊?

問題2:

這是影響的代碼編譯器的定位和準確的因素(如何)我可以使用這些特定的知識來克服這裏列出的問題呢?

假設爲了這個問題「不必擔心代碼對齊/相關的推測小速度好處」是而不是一個允許的答案。

+1

注:我也張貼了這個給Embarcadero公司的BASM論壇: HTTP: //forums.codegear.com/thread.jspa?threadID = 29333 – PhiS 2009-12-05 13:43:14

回答

7

德爾福XE的,代碼比對現在的問題是使用$CODEALIGN編譯器指令(見this Delphi documentation page)迎刃而解:

{$CODEALIGN 16} 
procedure MyAlignedProc; 
begin 
.. 
end; 
6

一件事,你可以做的,就是在每個例程的末尾添加一個「神奇」的簽名,明確ret指令後:

asm 
    ... 
    ret 
    db <magic signature bytes> 
end; 

現在,您可以創建包含指向每個例程的數組,在運行時掃描一次例程以獲得魔術簽名,以找出每個例程的結尾,從而找出它的長度。然後,您可以使用PAGE_EXECUTE_READWRITE將它們複製到使用VirtualAlloc分配的新內存塊,以確保每次例程都以16字節邊界開始。

+0

這似乎也是一種選擇,謝謝。我會進一步調查這種方法。 – PhiS 2009-12-06 12:31:04