2011-03-27 53 views
7

我正在使用Delphi 2010.是否可以告訴Delphi不爲函數生成序言?我正在寫一些純彙編函數是這樣的:刪除用純彙編編寫的函數的序言

procedure SomeAssembly; stdcall; 
begin 
    asm 
     ... 
    end; 
end; 

,我想告訴德爾福不會產生此功能的開端和結尾,就像C++的__declspec(naked)功能。

所以沒有人浪費他們的時間,我不需要幫助讓這些功能工作的序幕;我已經可以做到這一點。這只是一個很大的不便,並且會使維護變得非常麻煩。我將不得不手動檢查由編譯器生成的序言以查看它們的長度,如果更改,我的程序將崩潰。

我也知道我可以將這個函數寫成一個字節數組中的一系列字節,但這會比不得不去查找Delphi的序言長度更糟糕。

回答

19

德爾福不生成功能的序言或結尾沒有參數和宣佈與註冊調用約定。如果你想要沒有序言的函數,把它們聲明爲零參數,register-calling-convention函數。此外,跳過begin - end區塊並直接進入裝配。

procedure SomeAssembly; // register; (implied) 
asm 
    // ... 
end; 

由於您對功能的性質進行了有效的說明,調用它們可能會很棘手。如果您已經實現了一個函數,就像它接收到參數並使用了不同的調用約定,那麼您必須確保編譯器在調用站點上知道這一點。爲此,請聲明一個反映您的函數的「真實」類型而不是聲明類型的函數指針。例如,如果你的函數真的是兩個參數STDCALL功能,聲明是這樣的:

type 
    TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall; 
var 
    SomeAssemblyProc: TSomeAssemblyProc; 

現在,所以它指向你的函數分配一個變量:

SomeAssemblyProc := TSomeAssemblyProc(@SomeAssembly); 
if SomeAssembly(2, 'foo') then ... 

除了跳繩序言和尾聲,編譯器將爲此函數生成不正確的RET指令(因爲調用約定不同),所以您必須確保在代碼中說明ret 8,而不是讓編譯器的默認ret指令發生。


找到德爾福的開場白的長度是微不足道的,如果你有一個工作的調試器:

  1. 在函數的開始設置一個斷點。
  2. 調用該函數。
  3. 當調試器停在斷點處時,切換到CPU視圖。
  4. 看看組成序幕的指示。
  5. 計算這些指令旁顯示的字節數。
+0

爲什麼所有人都不能這樣回答?非常有幫助,謝謝Rob。 – 2011-03-27 17:41:56

+0

@K。 Charles:不同程度的專業知識?這是一個瘋狂的猜測,但沒有任何人打算冒犯任何人。 – 2011-03-27 17:53:43

+0

當你有函數指針時,沒有額外的間接級別嗎?我個人認爲tasm會更適合。 – 2011-03-27 18:08:48

0

procedure SomeAssembly; stdcall; 
asm 
    ... 
end; 

做的伎倆?

+0

如果我記得正確,'stdcall'會導致編譯器包含一個保存和恢復幀指針的序言和結尾,即使沒有參數。 – 2011-03-27 20:36:52

1

按照this embarcadero docwiki可以跳過周圍beginend,編譯器會忽略它的一些東西。但是,如果你真的想要純粹的彙編器,爲什麼不把你的函數放到一個單獨的彙編文件中,用tasm進行彙編(exe文件名爲tasm32)並鏈接到它。然後,您將在delphi代碼中使用assembler指令。

+0

@downvoters,請解釋。 TASM是Delphi的一部分,它是使用100%純彙編程序的自然方式。這是戰略投票嗎? – 2011-03-28 04:43:01