20

x86のアセンブリ言語を学びたいと思っています。私は Mac を使用していますが、ほとんどの x86 チュートリアル/書籍では Windows 向けのコードが使用されていると想定しています。

コードが実行されている OS は、コードの動作にどのように影響するか、またはコードが機能するかどうかを決定しますか? Windows ベースのチュートリアルに従って、いくつかのコマンドを変更して、比較的簡単に Mac で動作するようにすることはできますか? より一般的に言えば、特に Mac アセンブリ プログラマーが知っておくべき注意点はありますか? ありがとう!

4

5 に答える 5

21

(もちろん、以下のすべては、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 スタイルのシステム コールには、メモリを動的に割り当てるのが好きな場合に加えてopencreatreadwrite、および all-importantを含める必要があります (ただし、これらに限定されないことは間違いありません!) 。exitmmap

すべての 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参照してください。SYSENTERLinux 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 コードを記述します。) それ以外は、マシンはむき出しになっています。進んで計算してください!

于 2009-07-26T10:36:50.710 に答える
6

一般的に言えば、同じアセンブラーと同じアーキテクチャ (NASM や x86-64 など) を使用している限り、Windows と Mac の両方でアセンブリをアセンブルできるはずです。

ただし、実行形式や実行環境が異なる場合があるので注意が必要です。例として、Windows は特定の特権命令を Mac とは異なる方法でエミュレート/処理し、異なる動作を引き起こす可能性があります。

于 2009-07-24T01:25:55.373 に答える
2

Intelアセンブリ言語の大きな違いは、AT&T構文とIntel構文の間にあります。使用するチュートリアルと同じ構文を使用するMac用のアセンブラが必要になります。BSDバリアントであるMacOSDarwinはAT&T構文を使用し、MicrosoftアセンブラーはIntel構文を使用していると思うので、注意する必要があります。

注意すべきもう1つの違いは、システムのアプリケーションバイナリインターフェイス(ABI)です。これは、呼び出し規約、スタックレイアウト、システムコールなどをカバーしています。特に位置に依存しないコードダイナミックリンクに関しては、OS間で大幅に異なる場合があります。PICがPowerPCMacOSで特に複雑だったという漠然とした不幸な思い出がありますが、Intelではもっと簡単かもしれません。

アドバイスの1つ:x86_64(AMD64とも呼ばれます)を学ぶ—アセンブリコードを手作業で作成する方がはるかに楽しく、将来にわたって利用できるようになります。

于 2009-07-24T02:22:15.640 に答える
2

また、違いの大きな部分は、プログラムが外部の世界と通信する方法にあります。

たとえば、ユーザーにメッセージを表示したり、ファイルを読み取ったり、より多くのメモリを割り当てたりする場合は、何らかのシステム コールを作成して OS に要求する必要があります。それはOSによってかなり異なります。

同じアセンブラを使用している限り、言語構文自体は基本的に同じである必要があります。アセンブラが異なれば、構文やマクロの順序がわずかに異なることもありますが、慣れるのが難しいことは何もありません。

于 2009-07-24T01:58:13.210 に答える