(もちろん、以下のすべては、IA-32 および AMD64 プロセッサおよびオペレーティング システム用の x86 および x86-64 アセンブリ言語にのみ適用されます。)
現在表示されている他の回答はすべて正しいですが、私の意見では、要点を見逃しています。AT&T と Intel の構文はまったく問題ではありません。適切なツールは、両方の構文で動作するか、対応するツールまたは代替品を備えています。とにかく、彼らは同じように組み立てます。(ヒント: 本当に Intel 構文を使用したい場合は、プロセッサの公式ドキュメントはすべて使用します。AT&T 構文は、大きな頭痛の種の 1 つにすぎません。) はい、アセンブラとリンカに渡す正しいフラグを見つけるのは難しい場合がありますが、いつになるかがわかります。あなたはそれを手に入れており、OSごとに一度だけ行う必要があります(どこかに書き留めておくことを忘れないでください!)。
もちろん、アセンブリ命令自体は完全に OS に依存しません。CPUは、実行中のオペレーティング システムを気にしません。非常に低レベルのハッカー (つまり、OS 開発) を行っていない限り、OS と CPU がどのように相互作用するかという基本的なことは、ほとんどまったく関係ありません。
外の世界
アセンブリ言語の問題は、OS カーネルやその他のユーザー空間コードなど、外の世界と対話するときに発生します。ユーザー空間は最もトリッキーです: ABI を正しく取得する必要があります。そうしないと、アセンブリ プログラムはほとんど役に立ちません。この部分は、トランポリン/サンク (基本的に、サポートする予定のすべての OS で書き直さなければならない抽象化の別のレイヤー) を使用しない限り、OS 間で移植できません。
ABI の最も重要な部分は、C スタイル関数の呼び出し規則が何であるかです。それらは最も一般的にサポートされているものであり、アセンブリを作成している場合におそらくインターフェイスするものです。Agner Fog は、彼のサイトでいくつかの優れたリソースを管理しています。呼び出し規則の詳細な説明は特に役立ちます。Norman Ramsey はその回答の中で、PIC と動的ライブラリについて言及しています。私の経験では、そうしたくない場合は通常、それらを気にする必要はありません。静的リンクは、アセンブリ言語の一般的な用途 (内側のループやその他のホットスポットのコア関数の書き換えなど) では問題なく機能します。
呼び出し規則は 2 つの方向で機能します。アセンブリから C を呼び出すか、C からアセンブリを呼び出すことができます。後者は少し簡単になる傾向がありますが、大きな違いはありません。アセンブリから C を呼び出すと、C 標準ライブラリ出力関数などを使用できますが、C からアセンブリを呼び出すことは、通常、単一のパフォーマンス クリティカルな関数のアセンブリ実装にアクセスする方法です。
システムコール
プログラムが行うもう 1 つのことは、システム コールの作成です。外部の C 関数を決して呼び出さない完全で便利なアセンブリ プログラムを作成することはできますが、Fun Stuff を他の誰かのコードに外部委託しない純粋なアセンブリ言語プログラムを作成する場合は、システム コールが必要になります。残念ながら、システム コールは OS ごとにまったく異なります。Unix スタイルのシステム コールには、メモリを動的に割り当てるのが好きな場合に加えてopen
、creat
、read
、write
、および all-importantを含める必要があります (ただし、これらに限定されないことは間違いありません!) 。exit
mmap
すべての OS は異なりますが、最近のほとんどの OS は一般的なパターンに従います。必要なシステム コールの数を通常EAX
は 32 ビット コードでレジスタにロードし、次にパラメータをロードします (方法は大きく異なります)。割り込み要求を発行します。これINT 2E
は、Windows NT カーネルINT 80h
用、または Linux 2.x と FreeBSD (そして、OSX もそうだと思います) 用です。その後、カーネルが引き継ぎ、システム コールを実行し、実行をプログラムに返します。OS によっては、システム コールの一部としてレジスタまたはスタックが破棄される場合があります。プラットフォームのシステムコールのドキュメントを読んで確認する必要があります。
SYSENTER
Linux 2.6 カーネル (および、Windows XP 以降では、Windows で実際に試したことはありませんが) も、システム コールを行うための新しい高速な方法をサポートしています。これSYSENTER
は、新しい Pentium チップで Intel によって導入された命令です。AMD チップSYSCALL
には . . SYSENTER
セットアップと使用はかなり複雑です (たとえば、Linux 2.6 のサポートの実装に関する Linus Torvalds をSYSENTER
参照してください。SYSENTER
Linux 2.6 カーネルに直接発行するアセンブリ関数を書いたことがあります。それを機能させるさまざまなスタックとレジスタのトリックを理解していません...しかし、うまくいきました!
SYSENTER
を発行するよりも多少高速でINT 80h
あるため、利用可能な場合は使用することをお勧めします。高速で移植性の高いコードを簡単に記述できるようにするために、Linux は呼び出さlinux-gate
れた VDSO をすべてのプログラムのアドレス空間にマップします。この VDSO で特別な関数を呼び出すと、利用可能な最速のメカニズムによってシステム コールが発行されます。残念ながら、それを使用することは、一般的に価値があるよりも面倒です:INT 80h
小さなアセンブリ ルーチンで実行する方がはるかに簡単なので、わずかな速度のペナルティに見合うだけの価値があります。究極のパフォーマンスが必要でない限り...そしてそれが必要な場合でも、とにかく VDSO を呼び出す必要はなく、ハードウェアを知っているので、恐ろしく安全でないことを実行してSYSENTER
自分で問題を解決できます。
ほかのすべて
カーネルや他のプログラムとの対話によって課せられる要求を除けば、オペレーティング システム間の違いはほとんどありません。アセンブリはマシンの魂を露出させます。好きなように作業でき、独自のコード内では特定の呼び出し規則に縛られません。FPU ユニットと SSE ユニットに自由にアクセスできます。PREFETCH
メモリから L1 キャッシュに直接データをストリーミングし、必要なときにホットであることを確認できます。自由にスタックを変更できます。あなたが発行することができますINT 3
(適切に構成されています。頑張ってください!)外部デバッガとインターフェースしたい場合。これらのことは、OS に依存しません。唯一の実際の制限は、Ring 0 ではなく Ring 3 で実行しているため、一部のプロセッサ制御レジスタが使用できないことです。(ただし、それらが必要な場合は、アプリケーション コードではなく、OS コードを記述します。) それ以外は、マシンはむき出しになっています。進んで計算してください!