OS はアセンブリ コードの実行にどのような影響を与えますか?
質問
x86のアセンブリ言語を勉強したいと思っています。私は Mac を使用していますが、ほとんどの x86 チュートリアル/書籍では Windows 向けのコードが使用されていると思います。
コードが実行される OS はコードの動作にどのような影響を与えるのでしょうか、あるいはコードが機能するかどうかを決定するのでしょうか?Windows ベースのチュートリアルに従い、いくつかのコマンドを変更して Mac で比較的簡単に動作するようにすることはできますか?より一般的に、特に Mac アセンブリ プログラマーが知っておくべき注意すべき点はありますか?ありがとう!
解決
(もちろん、以下のすべてに当てはまります) のみ IA-32 および AMD64 プロセッサおよびオペレーティング システム用の x86 および x86-64 アセンブリ言語へ。)
現在表示されている他の回答はすべて正しいですが、私の意見では、要点を外しています。AT&T と Intel の構文は全く問題ではありません。まともなツールは両方の構文で動作するか、対応するものや代替品が存在します。そしてとにかく同じように組み立てます。(ヒント:本当に Intel 構文を使用したいのです。プロセッサの公式ドキュメントにはすべて記載されています。AT&T 構文は、まさに大きな頭痛の種です。) はい、アセンブラーとリンカーに渡す適切なフラグを見つけるのは難しい場合がありますが、それを取得した時点でわかります。また、OS ごとに 1 回行うだけで済みます。どこかに忘れずに書き留めてください。)
もちろん、アセンブリ命令自体は OS に依存しません。CPU 構わない 実行されているオペレーティング システム。非常に低レベルのハッキング (つまり OS 開発) を行っている場合を除き、OS と CPU がどのように相互作用するかという基本的なことは、ほとんどまったく関係ありません。
外の世界
アセンブリ言語の問題は、外部と対話するときに発生します。OS カーネル、およびその他のユーザー空間コード。ユーザー空間は最も厄介です:ABI を正しく取得する必要があります。そうしないと、アセンブリ プログラムは役に立ちません。この部分は通常、トランポリン/サンク (基本的に、サポートする OS ごとに書き換える必要がある別の抽象化レイヤー) を使用しない限り、OS 間で移植できません。
ABI の最も重要な部分は、C スタイルの関数の呼び出し規約が何であるかです。これらは最も一般的にサポートされているものであり、アセンブリを作成している場合はおそらくインターフェイスすることになるものです。Agner Fog は、いくつかの優れたリソースを維持しています。 彼のサイト;の 呼び出し規約の詳細な説明 は特に便利です。Norman Ramsey はその回答の中で、PIC と動的ライブラリについて言及しています。私の経験では、そうしたくないのであれば、通常はそれらを気にする必要はありません。静的リンクは、アセンブリ言語の一般的な使用法 (内部ループやその他のホットスポットのコア関数の書き換えなど) には問題なく機能します。
呼び出し規約は 2 つの方向で機能します。アセンブリから C を呼び出すことも、C からアセンブリを呼び出すこともできます。後者の方が少し簡単になる傾向がありますが、大きな違いはありません。アセンブリから C を呼び出すと、C 標準ライブラリの出力関数などを使用できますが、C からアセンブリを呼び出すと、通常、パフォーマンスが重要な単一関数のアセンブリ実装にアクセスします。
システムコール
プログラムが行うもう 1 つのことは、システム コールを行うことです。外部の C 関数を決して呼び出さない、完全で便利なアセンブリ プログラムを作成することはできますが、楽しいものを他の人のコードにアウトソーシングしない純粋なアセンブリ言語プログラムを作成したい場合は、次のことを行うことになります。 必要 システムコール。そして残念ながら、システム コールは OS ごとにまったく異なります。Unix スタイルのシステム コールを含める必要があります (ただし、これに限定されないことは間違いありません)。 open
, creat
, read
, write
, 、そして最も重要なこと 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
Intel によって新しい Pentium チップで導入された命令。AMDチップには、 SYSCALL
, ただし、これを使用する 32 ビット OS はほとんどありません (64 ビットでは標準だと思いますが、64 ビット プログラムから直接システム コールを行う必要がなかったので、これについてはわかりません)。 SYSENTER
設定と使用が大幅に複雑になります (たとえば、を参照) Linus Torvalds の実装について SYSENTER
Linux 2.6のサポート:「私は嫌な豚です、そしておまけにそれを誇りに思っています。」)私は個人的にその特異性を証明できます。以前、次のようなアセンブリ関数を書いたことがあります。 SYSENTER
Linux 2.6 カーネルに直接接続すると、 まだ それを機能させるためのさまざまなスタックとレジスタのトリックを理解していません...しかし、うまくいきました!
SYSENTER
発行するよりも若干速いです INT 80h
, 、そのため、利用可能な場合は使用することが望ましいです。高速で移植可能なコードの両方を簡単に作成できるようにするために、Linux は、次の VDSO をマップします。 linux-gate
すべてのプログラムのアドレス空間に。この VDSO で特別な関数を呼び出すと、利用可能な最速のメカニズムによってシステム コールが発行されます。残念ながら、これを使用すると、一般に、その価値よりもトラブルの方が多くなります。 INT 80h
小さな組み立てルーチンで実行するのが非常に簡単なので、多少の速度ペナルティを支払う価値があります。究極のパフォーマンスを必要としない限り...そして、それが必要な場合は、いずれにしても VDSO を呼び出したくないでしょうし、ハードウェアを知っているので、ひどく安全でないことを実行して問題を解決するだけで済みます。 SYSENTER
あなた自身。
ほかのすべて
カーネルや他のプログラムとの対話によって課せられる要求を除けば、オペレーティング システム間の違いはほとんどありません。組み立てはマシンの魂を明らかにします。好きなように作業でき、独自のコード内では特定の呼び出し規約に束縛されません。FPU および SSE ユニットに無料でアクセスできます。あなたはできる PREFETCH
データをメモリから L1 キャッシュに直接ストリーミングし、必要なときに確実にホットになるようにします。スタックを自由に書き換えることができます。発行できます INT 3
(適切に設定された) とインターフェースをとりたい場合。頑張ってください!) 外部デバッガ。これらはいずれも OS には依存しません。唯一の実際の制限は、リング 0 ではなくリング 3 で実行しているため、一部のプロセッサー制御レジスターが使用できないことです。(ただし、これらが必要な場合は、アプリケーション コードではなく OS コードを作成することになります。) それ以外は、マシンは裸の状態で表示されます。さあ、計算してみよう!
他のヒント
は、WindowsとMacの両方にアセンブリを組み立てることができる必要があります。
しかし、実行可能形式と実行環境が異なる場合がありますことを心に留めておくことが重要です。例として、Windowsはエミュレート/異なっMacに特定の特権命令を処理し、異なる動作の原因かもしれません。
また差の大部分は、プログラムが外の世界との通信方法です。
たとえば、ユーザーにメッセージを表示したり、ファイルを読み込むか、より多くのメモリを割り当てたい場合は、システムコールのいくつかの種類を作ることによってそれを行うには、OSに依頼することがあります。それはよ OS年代の間で大きく異なる場合がます。
言語の構文自体は、限り、あなたは同じアセンブラを使用していると基本的に同一である必要があります。別のアセンブラは時々構文または別のマクロだけに慣れるにはあまりにも難しい何も上のわずかに異なる順序付けを持っています。
インテルのアセンブリ言語でのグレートディバイドは、AT&T構文とIntel構文との間にあります。あなたが使用するすべてのチュートリアルと同じ構文を使用して、あなたのMac用のアセンブラをお勧めします。私はMacOSのダーウィン、BSD変異体は、AT&Tの構文を使用して信じている、とMicrosoftアセンブラがインテルの構文を使用しているので、あなたは注意する必要があります。
の用心するために、他の違いはそれほどで呼び出し規約、スタックレイアウト、システムコールなどをカバーし、システムのアプリケーションバイナリインタフェース(ABI)が、あります。彼らはそれがを位置独立コードと動的リンクのに来る場合は特に、OSの者の間で、実質的に異なる可能性があります。私は、PICは、特にPowerPCのMacOSで複雑になった漠然とした不満の思い出を持っていますが、多分それはインテルに簡単です。
アドバイスのワンピース: にx86_64版を学ぶ(もAMD64として知られている)-itは手でアセンブリコードを書くために、そしてあなたがより多くの将来防音だろうより多くの楽しいです。
。、すべてのチュートリアルに私を開催落とし穴は正しいバイナリ形式でコンパイルすることができることはなかったです。ほとんどのチュートリアルは(Linux用)elf
と(BSD用)aoutb
を与える、まだ後者は(論理的な選択?)OS Xは文句を言います:
ld: hello.o bad magic number (not a Mach-O file)
まだMach-O
は、フォーマットとして失敗し、あなたがman nasm
場合にのみbin
、aout
とelf
のファイル形式を取得していない - man ld
にはより有用である - macho
は、OS X用のMach-Oフォーマットを作成するためのオプションです。
nasm -f macho hello.asm
私は旅を書きましたここを(組立およびその他の情報のための素晴らしいTextMateのバンドルへのリンクが含まれます)が、 - 簡単になるように - 上記のあなたが始めるために必要なものです。
。