web-dev-qa-db-ja.com

NASM対GAS(実用的な違い)

私はIntel vs AT&T戦争(どちらもIntel構文をサポートするようになりました)を促したり、どちらが「より良い」かを尋ねたりしようとはしていません。どちらか一方を選択する際の実際的な違いを知りたいだけです。 。

基本的に、私が数年前にいくつかの基本的なx86アセンブリを手に取ったとき、私が読んでいた本以外に理由もなくNASMを使用しました。それ以来、私はアセンブリを使用する理由がほとんどないため、GASを試す機会がありませんでした。

どちらもIntel構文をサポートし(私個人的にはそれを好む)、少なくとも理論的には同じバイナリを生成する必要があることを覚えておいてください(おそらくそれらはおそらく生成されませんが、意味は変更されるべきではありません)。どちらか一方?

コマンドラインオプションですか?マクロ?非ニーモニックキーワード?または、他の何か?

ありがとう:)

36
Elliott

NASMは実際には、Intelの公式ドキュメントで使用されているMASM構文とは異なり、独自のバリエーションのIntel構文を使用しています。オペコード名とオペランドの順序はIntelと同じであるため、一見すると命令は同じに見えますが、重要なプログラムには違いがあります。たとえば、MASMでは、MOV ax, fooが使用する命令はfooのタイプに依存しますが、NASMにはタイプがなく、これは常に即値移動命令にアセンブルされます。オペランドのサイズを暗黙的に決定できない場合、MASMはDWORD PTRのようなものを使用する必要がありますが、NASMはDWORDを使用して同じことを意味します。命令ニーモニックと基本的なオペランドの形式と順序を超える構文のほとんどは異なります。

機能に関しては、NASMとGASはほとんど同じです。 NASMはより広範囲で成熟していますが、どちらにもアセンブラマクロ機能があります。多くのGASソースコードファイルは、GAS独自のマクロサポートの代わりにCプリプロセッサを使用します。

2つのアセンブラの最大の違いは、16ビットコードのサポートです。 GASはx86セグメントの定義をサポートしていません。 GASを使用すると、単純な単一セグメントの16ビットバイナリイメージの作成に制限されます。基本的には、ブートセクターと.COMファイルだけです。 NASMはセグメントを完全にサポートしており、セグメント化された16ビット実行可能ファイルを作成するために適切なリンカーで使用できるOMF形式のオブジェクトファイルをサポートしています。

OMFオブジェクトファイル形式に加えて、NASMはGASがサポートしていない多くの形式をサポートしています。 GASは通常、基本的にELF、PE-COFF、またはMACH-Oを実行するマシンのネイティブ形式のみをサポートします。別のフォーマットをサポートする場合は、そのフォーマット用の「クロスコンパイル」バージョンのGASを構築する必要があります。

もう1つの注目すべき違いは、NASでDWARFおよびWindows 64ビットアンワインド情報(後でWindows x64 ABIで必要)の作成をサポートしているのに対し、NASMではセクションを作成してデータを自分で入力する必要があることです。

26
Ross Ridge

Intel構文:mov eax、1(命令の宛先、ソース)

AT&T構文:movl $ 1、%eax(命令ソース、宛先)

Intelの構文はかなり自明です。上記の例では、移動されるデータの量は、レジスターのサイズ(eaxの場合は32ビット)から推測されます。使用されるアドレッシングモードは、オペランド自体から推測されます。

AT&T構文に関しては、いくつかの癖があります。まず、l命令の最後にあるmovサフィックスに注意してください。これはlongを表し、32ビットのデータを表します。他の命令サフィックスには、ワードのw(16ビット-not CPUのワードサイズと混同するために!)、クワッドワードのq( 64ビット)およびb(1バイトの場合)。常に必要とは限りませんが、通常、AT&T構文を使用するアセンブリコードが表示され、命令によって操作されるデータの量が明示的に示されます。

ソースオペランドと宛先オペランドで使用されるアドレッシングモードに関しては、より明確にする必要があります。 $は、使用中の命令自体の値と同様に、immediateアドレス指定を意味します。上記の例では、この$なしで書き込まれた場合、directアドレッシングが使用されます。つまり、CPUはメモリアドレス1で値をフェッチしようとします(これにより、セグメンテーションが発生する可能性が高くなります)障害)。 %registerアドレス指定を意味します。これを上記の例に含めなかった場合、eaxsymbolとして扱われます。リンク時におそらくundefined referenceになります。つまり、必須であること明示的で使用されるアドレッシングモードについて両方ソースと宛先のオペランドです。

メモリオペランドの指定方法も異なります。

Intel:[ベースレジスタ+インデックス*インデックスのサイズ+オフセット]

AT&T:オフセット(ベースレジスタ、インデックス、インデックスのサイズ)

Intel構文では、メモリアドレスを見つけるために実行されている計算が少し明確になります。 AT&T構文を使用しても結果は同じですが、計算が行われていることを知っていることが期待されます。

少なくとも理論的には、同じバイナリを生成する必要があります

これはツールチェーンに完全に依存しています。

どちらか一方を支持する理由は何ですか?

もちろん個人的な好みですが、私の意見では、メモリをアドレス指定するときにどの構文をより快適に感じるかによります。 AT&T構文の強制的な明示を好みますか?または、あなたはあなたのためにあなたのアセンブラーがこの低レベルの特徴を理解することを好みますか?

コマンドラインオプションですか?マクロ?非ニーモニックキーワード?

これは、アセンブラー(GAS、NASM)自体に関係しています。繰り返しますが、個人的な好み。

23
uname01