19


4

私はx86用のアセンブリ言語を習得したいと思っています。 私はMacを使っていますが、ほとんどのx86チュートリアル/本はWindows向けのコードを使っていると思います。

コードが実行されるOSは、コードの機能にどのように影響しますか、それともコードが機能するかどうかを判断しますか。 私はWindowsベースのチュートリアルに従うことができます、そして、それが比較的容易にMacのために働くようにいくつかのコマンドを修正することができますか? もっと一般的に言えば、Macのアセンブリプログラマ、特に知っておくべきトリッキーなものはありますか? ありがとうございます。

5 Answer


20


_(もちろん、以下はすべてx86およびx86-64アセンブリ言語にのみ適用されます(IA-32およびAMD64プロセッサおよびオペレーティングシステムの場合))。

現在目に見える他の答えはすべて正しいです、しかし、私の意見では、ポイントを逃します。 AT とにかく同じように組み立てます。 (Protip:あなたは本当にIntelの構文を使いたいのです。 公式のプロセッサー文書はすべて行います。 AT

アセンブリ命令自体は、もちろん、完全にOSに依存しません。 CPUは、実行しているオペレーティングシステムを気にしません。 極端に低レベルのハッカー行為(つまり、OS開発)をしているのでなければ、OSとCPUがどのようにやり取りするのかということの本質はほとんど無関係です。

外の世界

アセンブリ言語の問題は、OSのカーネルや他のユーザ空間のコードなど、外部と対話するときに起こります。 ユーザースペースは最も難しい:あなたはABIを正しくしなければならないか、あなたのアセンブリプログラムはほとんど役に立たない。 トランポリン/サンク(基本的には、サポートしようとするOSごとに書き直さなければならない別の抽象化層)を使用しない限り、この部分は一般にOS間で移植できません。

ABIの最も重要な部分は、呼び出し規約がCスタイル関数用のものであるということです。 それらは最も一般的にサポートされているものであり、あなたがアセンブリを書いているなら、あなたはおそらくあなたがインターフェースしようとしているものです。 Agner Fogはhttp://www.agner.org/optimize/ [このサイト]でいくつかの良いリソースを管理しています。 http://www.agner.org/optimize/calling_conventions.pdf [呼び出し規約の詳細な説明]が特に役立ちます。 彼の答えでは、Norman RamseyはPICと動的ライブラリに言及しています。私の経験では、あなたがしたくないのであれば、あなたは通常それらに悩む必要はありません。 静的リンクは、アセンブリ言語の一般的な用途(内部ループや他のホットスポットのコア機能の書き換えなど)にはうまく機能します。

呼び出し規約は2つの方向で機能します。アセンブリからCを呼び出すことも、Cからアセンブリを呼び出すこともできます。 後者は少し簡単になる傾向がありますが、大きな違いはありません。 アセンブリからCを呼び出すと、C標準ライブラリ出力関数のようなものを使用できますが、Cからアセンブリを呼び出すと、通常はパフォーマンスが重要な単一の関数のアセンブリ実装にアクセスする方法になります。

システムコール

あなたのプログラムがするもう一つのことはシステムコールを作ることです。 外部のC関数を呼び出さない完全で有用なアセンブリプログラムを書くことができますが、Fun Stuffを他の人のコードにアウトソーシングしない純粋なアセンブリ言語プログラムを書きたい場合は、システムコールを_必要_することになります。 そして、残念なことに、システムコールはすべてのOSでまったく、そしてまったく異なります。 あなたが必要とするUnixスタイルのシステムコール( mmap`と共に open`、 creat、` read`、 write、そして最も重要な` exit`が含まれています。動的にメモリを割り当てるのが好きなら。

すべてのOSは異なりますが、最近のほとんどのOSは一般的なパターンに従います。つまり、必要なシステムコールの番号をレジスタ(通常は32ビットコードの「EAX」)にロードし、次にパラメータをロードします。そして最後に割り込み要求を発行します:それはWindows NTカーネルの場合は INT 2E、Linux 2.xとFreeBSDの場合は` INT 80h 'です(そして私はOSXと思います)。 その後、カーネルが処理を引き継ぎ、システムコールを実行して、実行をプログラムに返します。 OSによっては、システムコールの一部としてレジスタを捨てたりスタックしたりすることがあります。あなたが確実にするためにあなたはあなたのプラットフォーム用のシステムコールドキュメントを読むことを確実にしなければならないでしょう。

「SYSENTER」

Linux 2.6カーネル(そして、私はWindows XP以降は、私はWindows上で実際に試したことはないが)も、システムコールを行うための新しい、より速い方法をサポートしている。 AMDチップには SYSCALL`がありますが、32ビットOSではほとんど使用されていません(64ビットの標準ですが、64ビットプログラムから直接システムコールを行う必要はないと思います)。これで)。 `SYSENTER`の設定と使用はかなり複雑です(例えば、http://lkml.org/lkml/2002/12/18/218 [Linux 2.6に対する SYSENTER`サポートの実装についてのLinus Torvalds]を参照してください。]私は嫌な豚です、そして、それをブートすることを誇りに思います。 ")私は個人的にその特異性を証明することができます。私はかつてLinux 2.6カーネルに直接SYSENTERを発行するアセンブリ関数を書きましたが、それでもうまくいくようにしたさまざまなスタックとレジスタトリックを理解できません…​ しかしそれはやりました!

SYSENTER`は INT 80h`を発行するよりもやや速いので、利用可能であればその使用が望ましいです。 高速で移植性の高いコードをより簡単に書くために、Linuxは `linux-gate`と呼ばれるVDSOをすべてのプログラムのアドレス空間にマッピングします。このVDSOで特別な機能を呼び出すと、利用可能な最速のメカニズムによってシステムコールが発行されます。 残念ながら、それを使うことは価値があるより一般的にもっと面倒です: `INT 80h`は小さいアセンブリルーチンでするのがとても簡単であるのでそれは小さいスピードペナルティの価値があります。 あなたが究極のパフォーマンスを必要としない限り…​ もしそれが必要なら、あなたはおそらくVDSOに電話をかけたくないでしょう、そしてあなたはあなたのハードウェアを知っています、それであなたは恐ろしく危険なことをしそしてあなた自身で「SYSENTER」を発行することができます。

ほかのすべて

カーネルや他のプログラムと対話することによって課される要求以外に、オペレーティングシステム間の違いは非常にわずかです。 アセンブリは機械の魂を露出させます:あなたはあなたが好きなように働くことができます、そしてあなた自身のコードの中であなたはどんな特定の呼び出し規約によっても束縛されません。 あなたはFPUとSSEユニットに無料でアクセスできます。データをメモリからL1キャッシュに直接ストリーミングして、必要なときに確実にホットにすることができます。あなたは自由にスタックを突破することができます。 (適切に設定された;幸運なことに)外部デバッガとやり取りしたい場合は、 `INT 3`を発行できます。 これらのことのどれもあなたのOSに依存しません。 あなたが持っている唯一の本当の制限はあなたがRing 0ではなくRing 3で走っているということです、そしてそれ故にあなたにはいくつかのプロセッサ制御レジスタが利用できなくなるでしょう。 (ただし、それらが必要な場合は、アプリケーションコードではなく、OSコードを書いています。)それ以外は、マシンは裸になっています。


6


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

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


2


また、その違いの大部分は、プログラムがどのように外界と通信するかという点です。

たとえば、ユーザにメッセージを表示したり、ファイルを読んだり、さらに多くのメモリを割り当てたりしたい場合は、何らかのシステムコールを実行してそれを実行するようOSに依頼する必要があります。 それはOSによってかなり違うでしょう。

同じアセンブラを使用している限り、言語構文自体は基本的に同じでなければなりません。 アセンブラによって構文が異なる場合やマクロによって順序が若干異なる場合がありますが、慣れるのは難しいことではありません。


2


インテルのアセンブリ言語での格差はAT間 あなたが使用するチュートリアルと同じ構文を使用するあなたのMac用のアセンブラが欲しいでしょう。 私はBSDの変種であるMacOS DarwinがATを使っていると思うので

注意が必要なもう1つの違いは、呼び出し規約、スタックレイアウト、システムコールなどを網羅するシステムのアプリケーションバイナリインタフェース(ABI)です。 特に位置に依存しないコードや動的リンクに関しては、OSによって大きく異なる可能性があります。 私はPICがPowerPC MacOS上では特に複雑であるという漠然とした不幸な思い出を持っていますが、Intel上ではもっと単純かもしれません。

1つのアドバイス:* x86_64 *(AMD64とも呼ばれます)を学ぶ - 手作業でアセンブリコードを書くのはもっと楽しくなり、将来的にはもっと確実になるでしょう。


1


プログラミングのための観光客の訪問中に私がAssemblyに没頭したとき、すべてのチュートリアルで私を悩ませていた落胆は正しいバイナリフォーマットでコンパイルすることができなかったことでした。 ほとんどのチュートリアルは elf(Linux用)と` aoutb`(BSD用)を与えていますが、後者(論理的な選択は?)では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

私はhttp://daveeveritt.tumblr.com/post/67819832/webstraction-2-from-unix-history-and-assembly-language [ここに旅行を書き上げました](Assemblyなどのための素晴らしいTextMateバンドルへのリンクを含みます) info)、しかし - 簡単に言うと - 上記はあなたが始めるために必要なものです。