5

この回答で使用しているように NASM を使用するとしましょう: how to write hellow world in assembly under windows

c# やその他の .net 言語と組み合わせたアセンブリに関して、いくつかの考えと質問がありました。

まず、HelloWorldこのパラメーターを受け取る次の関数を持つライブラリを作成できるようにしたいと考えています。

  • 名前

C# では、メソッド シグネチャは次のようvoid HelloWorld(string name)になります。

名前からのHello World

私は少し調べましたが、これを始めるのに十分できれいな資料を見つけることができません. 私は基本的な組み立てを以前からほとんど知ってgasいます。

したがって、正しい方向への指針は非常に高く評価されます。

要約すると

  • 1 つ以上のパラメーターを受け取るルーチンを ASM ( NASM ) で作成します。
  • 上記の機能のライブラリをコンパイルして作成します
  • ライブラリを任意の .net 言語に含める
  • 含まれているライブラリ関数を呼び出す

ボーナス機能

  • 返された値をどのように処理しますか?
  • ASMメソッドをインラインで書くことはできますか?

アセンブリまたは c でライブラリを作成する場合、特定の「定義済み」の方法、つまり c 呼び出し規則に従いますよね?

4

4 に答える 4

11

次のようなもので、動作する DLL が得られるはずです。

extern _printf

section .text
global _hello
_hello:
    push ebp
    mov ebp, esp

    mov eax, [ebp+12]
    push eax
    push helloWorld
    call _printf
    add esp, 8
    pop ebp
    ret

export _hello

helloWorld: db 'Hello world from %s', 10, 0

次に、P/Invoke を使用して「hello」関数を呼び出すだけです。それ自体はクリーンアップされないため、CallingConvention を Cdecl に設定する必要があります。また、ANSI 文字列を使用していることを伝える必要があります。テストされていませんが、正常に動作するはずです。

using System.Runtime.InteropServices;

namespace Test {
    public class Test {
        public static Main() {
            Hello("C#");
        }

        [DllImport("test.dll", EntryPoint="hello", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
        public static extern Hello(string from_);
    }
}
于 2010-05-18T11:24:09.677 に答える
3

最初に、必要なことを実行するための基本的なガイドラインについて説明します。次に、HelloWorldの例を実行する方法を説明します。

最初のステップは、関数を記述し、それからdllを作成することです。アセンブリ内の関数は、呼び出し標準の1つに準拠する必要があります。stdcallが最も一般的なものです(stdcallおよびその他の呼び出し標準について詳しくは、こちらをご覧ください)asmを使用してdllを作成する例は、こちらにあります。

2番目のステップは、P/Invokeを使用して管理対象言語でメソッドをインポートすることです。あなたはここでそれについてもっと読むことができます

以上です..

上記の例では、すべての入力パラメーターを受け取り、それをstdoutに出力する方法を知っている他の関数(上記の標準c libからのprintf、またはここのようなwinapi呼び出しを使用)に渡すasm関数を作成する必要があります)。

その後、上記のように、dllをC#にインポートする必要があります。特に注意が必要なのは、文字列の文字エンコードとデータのクリーンアップです。それらはすべて、私が提供した3番目のリンク(マーシャリングテキストセクション)に記載されています。

ボーナスパート:

  • 戻り値の処理は、使用される呼び出し規約によって異なります
  • C#でインラインアセンブリを作成することはできません。ただし、ManagedC++を使用して記述できます。
于 2010-05-18T11:38:44.140 に答える
1

これは非常に良い質問であり、私からの投票に値します。あなたの質問に関連して、コーディが彼のアセンブラールーチンを指摘したようにこれを行うことができる唯一の方法は、それに基づいてDLLを構築し、そこから次のような相互運用を使用して p/Invoke を使用することです

[DllImport("mylib.dll")]

ただし、残念ながら、C# やその他の言語の性質上、CLR ランタイム環境ではマネージ コードが使用されています。CLR やアセンブラでスタック フレームやレジスタを設定し、ネイティブ ワールドからマネージド ワールドにクロス ジャンプするのは面倒です。それは大変な作業ですが、誰かがそのようなことを見た場合は、回答の最後にコメントを残してください。それに応じてこの回答を修正します。

したがって、私の知る限り、アセンブラーによって、eax、ebx、スタック フレームなどのシステム レジスタを使用して CLR コードにアセンブラー ルーチンをインライン化する方法はありません。上記は彼の答えで提供されています。この場合、C/C++ に当てはまります。

ボイド foo(ボイド){
   _asm{
     xor ecx、ecx
     移動 eax, 1
     ....
   }
}

コードをさらに最適化するために、このように CLR の観点からそれを行うのは良いことですが、少なくとも理論的には、CLR が実際にこのようなものをホストすることは乗り越えられない仕事です。例外が 1 つあります。 . これを実行できる Managed C++ コンパイラで実行できますが、とにかくVB.NET/C#から実行することはできません:

プライベート ボイド mycsfunction(文字列 s){
    // マネージ コード アホイ
    StringBuilder sb = 新しい StringBuilder(s);
    ……
    _asm{
        EBPをプッシュ
        mov ebp、esp
        lea edx、オフセット sb
        ....
        移動 eax, 1
        ポップEBP
    }
}

ただし、この件に関しては、IL コードをネイティブ アセンブラーに生成することは可能ですが、これを書いている現在、これが逆に可能かどうかは 100% 確信が持てません。詳細な説明については、こちらを参照してください。発生する可能性があります

ただし、CLR アセンブリで作業する唯一の方法は、IL コードを手書きし、代わりにそれをコンパイルすることです。つまり、CLR ランタイムのアセンブラーを、ネイティブ アセンブラーがネイティブ (NON -CLR バイナリ)、これを達成する方法については、こちらの記事も参照してください。

于 2010-05-18T11:46:05.603 に答える
0

私が見たように、あなたの質問は2つあります。

  1. アセンブリを使用して関数を作成し、DLL に配置するにはどうすればよいですか?
  2. マネージ C# からアンマネージ DLL の関数を呼び出すにはどうすればよいですか?

2 に対する答えは、P/Invoke を使用することです。そのトピックについては、多くのドキュメントとチュートリアルが利用可能です。たとえば、 http: //msdn.microsoft.com/en-us/magazine/cc164123.aspx

于 2010-05-18T11:28:32.380 に答える