7

Delphi 2010 を使用しています。関数のプロローグを生成しないように Delphi に指示することはできますか? 次のような純粋なアセンブリ関数をいくつか書いています。

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

C++ の機能のように、この関数のプロローグとエピローグを生成しないように Delphi に指示したいと思い__declspec(naked)ます。

したがって、誰も時間を無駄にすることはありません。プロローグでこれらの関数を動作させるのに助けは必要ありません。私はすでにそれを行うことができます。それは単に大きな不便であり、メンテナンスが非常に面倒になります。コンパイラによって生成されたプロローグを手動で調べて、その長さを確認する必要があります。それが変更されると、プログラムがクラッシュします。

また、関数を一連のバイトとしてバイト配列に記述できることもわかっていますが、Delphi のプロローグの長さを調べなければならないよりもさらに悪いことです。

4

3 に答える 3

20

Delphi は、引数を持たず、レジスタ呼び出し規約で宣言された関数のプロローグまたはエピローグを生成しません。プロローグのない関数が必要な場合は、それらを引数なしのレジスタ呼び出し規則関数として宣言します。また、begin-endブロックをスキップして、アセンブリに直接進みます。

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

関数の性質について効果的に嘘をついているので、それらを呼び出すのは難しいかもしれません。パラメーターを受け取ったかのように関数を実装し、別の呼び出し規則を使用した場合は、コンパイラーが呼び出しサイトでそれを認識していることを確認する必要があります。これを行うには、宣言された型ではなく、関数の「実際の」型を反映する関数ポインターを宣言します。たとえば、関数が実際に引数が 2 つの stdcall 関数である場合は、次のように宣言します。

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

次に、その変数を割り当てて、関数を指すようにします。

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

プロローグとエピローグをスキップするだけでなく、コンパイラはこの関数に対して誤った命令を生成します (呼び出し規則が異なるため)。そのため、コンパイラの既定の命令を発生させるのではなく、コードでRET確実に宣言する必要があります。ret 8ret


動作するデバッガがあれば、Delphi のプロローグの長さを見つけるのは簡単です。

  1. 関数の先頭にブレークポイントを設定します。
  2. 関数を呼び出します。
  3. デバッガーがブレークポイントで停止したら、CPU ビューに切り替えます。
  4. プロローグを構成する指示を見てください。
  5. それらの命令の横に表示されるバイト数を数えます。
于 2011-03-27T17:34:41.590 に答える
1

この embarcadero docwikiによると、周囲beginをスキップできend、コンパイラはその一部をスキップします。しかし、本当に純粋なアセンブラーが必要な場合は、関数を別のアセンブラー ファイルに入れて、tasm (exe の名前は tasm32) でアセンブルし、それにリンクしてください。次に、このassemblerディレクティブを Delphi コードで使用します。

于 2011-03-27T17:37:30.990 に答える
0

しません

procedure SomeAssembly; stdcall;
asm
    ...
end;

トリックをしますか?

于 2011-03-27T17:34:30.570 に答える