x86アセンブリ言語


X86_assembly_language

x86アセンブリ言語命令の特定のリストについては、x86命令リストを参照してください
 「X86アセンブリ言語」  
x86アセンブリ言語は、下位互換性のある アセンブリ言語のファミリであり、1972年4月に導入されたIntel8008まである程度の互換性を提供します。 x86アセンブリ言語は、x86のオブジェクトコードを生成するために使用されます。プロセッサのクラス。すべてのアセンブリ言語と同様に、短いニーモニックを使用して、コンピューターのCPUが理解して従うことができる基本的な命令を表します。コンパイラは、高水準プログラムを機械語に変換する際の中間ステップとしてアセンブリコードを生成することが 。プログラミング言語と見なされるアセンブリコーディングは、マシン固有で低レベルです。アセンブリ言語は、通常、小さなリアルタイムの 組み込みシステムやオペレーティングシステムの カーネルやデバイスドライバーなど、詳細でタイムクリティカルなアプリケーションに使用されます。

コンテンツ
1 ニーモニックとオペコード
2 構文
3 レジスター
4 セグメント化されたアドレス指定
5 実行モード
5.1 モードの切り替え 5.2 例
6 命令タイプ
6.1 スタック命令 6.2 整数ALU命令 6.3 浮動小数点命令 6.4 SIMDの説明 6.5 データ操作手順
7 プログラムフロー
8 例
8.1 “こんにちは世界!” MASMスタイルのアセンブリでDOS用のプログラム 8.2 “こんにちは世界!” MASMスタイルのアセンブリでWindows用のプログラム 8.3 “こんにちは世界!” NASMスタイルのアセンブリでのWindows用プログラム 8.4 “こんにちは世界!” NASMスタイルのアセンブリでのLinux用プログラム 8.5 “こんにちは世界!” C標準ライブラリを使用したNASMスタイルのアセンブリでのLinux用プログラム 8.6 “こんにちは世界!” NASMスタイルのアセンブリでの64ビットモードLinux用のプログラム 8.7 フラグレジスタの使用 8.8 命令ポインタレジスタの使用
9 も参照してください
10 参考文献
11 参考文献
11.1 マニュアル 11.2 本
12 外部リンク

ニーモニックとオペコード
x86命令リスト
各x86アセンブリ命令はニーモニックで表され、多くの場合1つ以上のオペランドと組み合わされて、オペコードと呼ばれる1つ以上のバイトに変換されます。たとえば、NOP命令は0x90に変換され、HLT命令は0xF4に変換されます。文書化されたニーモニックのない潜在的なオペコードがあり、プロセッサが異なれば解釈も異なり、それらを使用するプログラムの動作に一貫性がなくなったり、一部のプロセッサで例外が発生したりする可能性がこれらのオペコードは、コードをより小さく、より速く、よりエレガントにする方法として、または単に作者の腕前を誇示するための方法として、コード作成コンテストに登場することがよく

構文
x86アセンブリ言語には、Intel構文とAT&T構文の2つの主要な構文ブランチが UnixはAT&T Bell Labsで作成されたため、Intel構文はDOSおよびWindowsの世界で支配的であり、AT&T構文はUnixの世界で支配的です。 Intel構文とAT&T構文の主な違いの要約は次のとおりです。 AT&T インテル
パラメータの順序 宛先の前のソース。
movl $ 5 、 %eax
ソースの前の宛先。
mov eax 、 5
パラメータサイズ :ニーモニックは、オペランドのサイズを示す文字で接尾されるQ QWORDため、L、長いため(DWORD)wは単語のための、およびBバイトのため。
addl $ 4 、 %esp
使用されるレジスタの名前から派生します(たとえば、rax、eax、ax、alはそれぞれq、l、w、bを意味します)。
espを追加、 4
印章 「$」が前に付いた即時値、「%」が前に付いたレジスタ。
アセンブラはシンボルのタイプを自動的に検出します。つまり、それらがレジスタ、定数、またはその他のものであるかどうか。
有効なアドレス DISP(BASE、INDEX、SCALE)の一般的な構文。例:
movl mem_location (%ebx 、%ecx 、4 )、 %eax
角括弧内の算術式。さらに、オペランドからサイズを判別できない場合は、byte、word、dwordなどのsizeキーワードを使用する必要が例:
mov eax 、 [ ebx + ecx * 4 + mem_location ]
多くのx86アセンブラは、NASM、FASM、MASM、TASM、YASMなどのIntel構文を使用します。もともとAT&T構文を使用していたGASは、バージョン2.10以降、.intel_syntaxディレクティブを介して両方の構文をサポートしています。 x86のAT&T構文の癖は、x87オペランドが逆になっていることです。これは、元のAT&Tアセンブラーから継承されたバグです。
AT&T構文は、同じmov順序で他のすべてのアーキテクチャにほぼ普遍的です。もともとはPDP-11アセンブリの構文でした。Intel構文はx86アーキテクチャに固有であり、x86プラットフォームのドキュメントで使用されているものです。

レジスター
X86アーキテクチャ§x86レジスタ
x86プロセッサには、バイナリデータのストアとして使用できるレジスタのコレクションがデータレジスタとアドレスレジスタを総称して、汎用レジスタと呼びます。各レジスタには、すべての機能に加えて、特別な目的が
AXの乗算/除算、文字列のロードと保存
MOVEのBXインデックスレジスタ
文字列操作とシフトのCXカウント
INおよびOUTのDXポートアドレス
SPはスタックの一番上を指します
BPはスタックフレームのベースを指します
SIはストリーム操作のソースを指します
DIは、ストリーム操作で宛先を指します
一般的なレジスタに加えて、さらに次のものが
IP命令ポインタ
フラグ
64kセグメントの開始位置を決定するセグメントレジスタ(CS、DS、ES、FS、GS、SS)(80286以前ではFSとGSはありません)
追加の拡張レジスタ(MMX、3DNow!、SSEなど)(Pentium以降のみ)。
IPレジスタは、コードセグメント内の次の命令のメモリオフセットを指します(命令の最初のバイトを指します)。プログラマがIPレジスタに直接アクセスすることはできません。
x86レジスタは、MOV命令を使用して使用できます。たとえば、Intel構文では次のようになります。
mov axe 、 1234h ; 値1234hex(4660d)をレジスターAXにコピーします
mov bx 、 ax ; AXレジスタの値をBXレジスタにコピーします

セグメント化されたアドレス指定
x86アーキテクチャで実および仮想8086モードとして知られるプロセス使用セグメンテーションアドレスメモリ、ないようにフラットなメモリ・モデルの多くの他の環境で使用します。セグメンテーションには、セグメントとオフセットの2つの部分からメモリアドレスを構成することが含まれます。セグメントは64KB(64×2 10)のアドレスグループの先頭を指し、オフセットはこの先頭アドレスから目的のアドレスまでの距離を決定します。セグメント化されたアドレス指定では、完全なメモリアドレスに2つのレジスタが必要です。1つはセグメントを保持し、もう1つはオフセットを保持します。フラットアドレスに変換し直すために、セグメント値は4ビット左にシフトされ(2 4または16の乗算に相当)、オフセットに追加されて完全なアドレスを形成します。これにより、アドレスを巧妙に選択することで64kの障壁を打ち破ることができます。ただし、プログラミングはかなり複雑になります。
ではリアルモード/ DSが含まれている場合、例えば、唯一の保護進数0xDEADはとDXは、彼らが一緒にメモリアドレス0xDEAD *の0x10 + 0xCAFE = 0xEB5CEを指してしまう数0xCAFEが含まれています。したがって、CPUはリアルモードで最大1,048,576バイト(1 MB)をアドレス指定できます。セグメント値とオフセット値を組み合わせることにより、20ビットのアドレスを見つけます。
元のIBMPCはプログラムを640KBに制限していましたが、拡張メモリ仕様を使用してバンク切り替えスキームを実装しましたが、Windowsなどの後のオペレーティングシステムが新しいプロセッサのより広いアドレス範囲を使用し、独自の仮想メモリを実装したときに使用されなくなりました。スキーム。
Intel 80286以降のプロテクトモードは、OS / 2で使用されていました。BIOSにアクセスできない、プロセッサをリセットせずにリアルモードに戻れないなど、いくつかの欠点があり、広く使用できませんでした。 80286は、16ビットセグメントでのメモリのアドレス指定にも制限されていました。つまり、一度に2つの16バイト(64キロバイト)しかアクセスできませんでした。80286の拡張機能にアクセスするために、オペレーティングシステムはプロセッサをプロテクトモードに設定し、24ビットアドレス指定を有効にして、2 24バイトのメモリ(16メガバイト)を有効にします。
保護モードセグメント・セレクタは、三つの部分に分けることができ、13ビットの指数、表インジケータエントリが入っているか否かを判断するそのビットGDTまたはLDTと2ビットの要求された特権レベル。x86メモリセグメンテーションを参照して
セグメントとオフセットを持つアドレスを参照する場合、セグメント:オフセットの表記が使用されるため、上記の例では、フラットアドレス0xEB5CEを0xDEAD:0xCAFEとして、またはセグメントとオフセットレジスタのペアとして書き込むことができます。DS:DX。
重要なアドレスを指すセグメントレジスタと一般レジスタのいくつかの特別な組み合わせが
CS:IP(CSはコードセグメント、IPは命令ポインタ)は、プロセッサがコードの次のバイトをフェッチするアドレスを指します。
SS:SP(SSはスタックセグメント、SPはスタックポインタ)は、スタックの最上位のアドレス、つまり最後にプッシュされたバイトを指します。
DS:SI(DSはデータセグメント、SIはソースインデックス)は、ES:DIにコピーされようとしている文字列データを指すためによく使用されます。
ES:DI(ESはExtra Segment、DIはDestination Index)は通常、前述のように、文字列コピーの宛先を指すために使用されます。
Intel 80386は、リアルモード、プロテクトモード、仮想モードの3つの動作モードを備えていました。プロテクトモード80286でデビューした80386は4まで対応できるように拡張されたGB、メモリのすべての新しい仮想8086モード(VM86は)主にエミュレート保護された環境内の1つ以上のリアルモードのプログラムを実行することを可能にしました一部のプログラムは互換性がありませんでしたが、リアルモードです(通常、メモリアドレス指定のトリックまたは不特定のopコードの使用の結果として)。
80386の拡張プロテクトモードの32ビットフラットメモリモデルは、AMDが2003年にx86-64をリリースするまで、x86プロセッサフ​​ァミリの最も重要な機能変更である可能性がプロテクトモード)Windowsは、仮想メモリと単純なマルチタスクを使用して、DOSアプリケーションを含む多くのアプリケーションを一度に実行できるようになりました。

実行モード
X86アーキテクチャ
x86プロセッサは、x86コードの5つの動作モード、リアルモード、プロテクトモード、ロングモード、仮想86モード、およびシステム管理モードをサポートします。これらのモードでは、一部の命令が使用可能で、他の命令は使用できません。命令の16ビットサブセットは、8086、8088、80186、80188、および80286である16ビットx86プロセッサで使用できます。これらの命令は、すべてのx86プロセッサで実モードで使用でき、16ビット保護モードで使用できます。 (80286以降)、保護モードに関連する追加の手順が利用可能です。上80386(以降拡張を含む)以降、32ビット命令もリアルモードを含むすべてのモードで利用可能です。これらのCPUでは、V86モードと32ビットプロテクトモードが追加され、これらのモードで機能を管理するための追加の命令が提供されます。SMMは、独自の特別な命令のいくつかとともに、一部のIntel i386SL、i486以降のCPUで使用できます。最後に、ロングモード(AMD Opteron以降)では、64ビット命令やその他のレジスタも利用できます。命令セットは各モードで類似していますが、メモリアドレス指定とワードサイズが異なり、異なるプログラミング戦略が必要です。
x86コードを実行できるモードは次のとおりです。
リアルモード(16ビット)
20ビットのセグメント化されたメモリアドレス空間(1 MBのメモリしかアドレス指定できないことを意味します。実際にはわずかに多い)、周辺ハードウェアへの直接ソフトウェアアクセス、およびハードウェアレベルでのメモリ保護やマルチタスクの概念はありません。BIOSを使用するコンピューターは、このモードで起動します。
プロテクトモード(16ビットおよび32ビット)
アドレス指定可能な物理メモリを16MBに拡張し、アドレス指定可能な仮想メモリを1GBに拡張します。特権レベルと保護されたメモリを提供し、プログラムが相互に破損するのを防ぎます。16ビットプロテクトモード(DOS時代の終わりに使用された)は、複雑なマルチセグメントメモリモデルを使用していました。32ビットプロテクトモードは、シンプルなフラットメモリモデルを使用します。
ロングモード(64ビット)
ほとんどの場合、32ビット(プロテクトモード)命令セットの拡張ですが、16ビットから32ビットへの移行とは異なり、64ビットモードでは多くの命令が削除されました。AMDによって開拓されました。
仮想8086モード(16ビット)
プロテクトモードスーパーバイザオペレーティングシステムの制御下でリアルモードプログラムとオペレーティングシステムを実行できるようにする特別なハイブリッドオペレーティングモード
システムマネジメントモード(16ビット)
電源管理、システムハードウェア制御、独自のOEM設計コードなどのシステム全体の機能を処理します。これは、システムファームウェアでのみ使用することを目的としています。オペレーティングシステムを含むすべての通常の実行は中断されます。次に、代替ソフトウェアシステム(通常はコンピューターのファームウェアまたはハードウェア支援デバッガーに存在します)が高い特権で実行されます。

モードの切り替え
プロセッサは電源を入れた直後にリアルモードで実行されるため、オペレーティングシステムの カーネルまたは他のプログラムは、リアルモード以外で実行する場合は、明示的に別のモードに切り替える必要がモードの切り替えは、いくつかの準備の後にプロセッサの制御レジスタの特定のビットを変更することによって実現され、切り替え後にいくつかの追加のセットアップ 例

レガシーBIOSを実行しているコンピューターでは、BIOSとブートローダーがリアルモードで実行されています。次に、64ビットオペレーティングシステムカーネルがCPUをチェックしてロングモードに切り替え、64ビットコードを実行する新しいカーネルモードスレッドを開始します。
UEFIを実行しているコンピューターでは、UEFIファームウェア(CSMとレガシーオプションROMを除く)、UEFIブートローダー、およびUEFIオペレーティングシステムカーネルはすべてロングモードで実行されています。

命令タイプ
一般に、最新のx86命令セットの機能は次のとおりです。
コンパクトなエンコーディング
可変長およびアライメントに依存しない(x86アーキテクチャのすべてのデータと同様に、リトルエンディアンとしてエンコードされます)
主に1アドレスと2アドレスの命令、つまり、最初のオペランドはデスティネーションでも
ソースと宛先の両方としてのメモリオペランドがサポートされています(小さな即時オフセットを使用してアドレス指定されたスタック要素の読み取り/書き込みに頻繁に使用されます)。
一般的なレジスタと暗黙的なレジスタの両方の使用法。すべての7つ(カウントがebp32ビットモード)汎用レジスタ、およびすべての15(カウントrbp)64ビットモードで汎用レジスタは、自由に使用することができる蓄電池又はそれらのほとんどもされ、アドレス指定のために暗黙的に(特定により使用されるより、または少ない)特別な指示; したがって、影響を受けるレジスタは、そのような命令シーケンス中にアクティブな場合、一時的に保存(通常はスタック)する必要が
ほとんどの整数ALU命令を介して暗黙的に条件付きフラグを生成します。
ジャンプ(x86-64アーキテクチャの改善として導入)を除いて、即時、オフセット、およびスケーリングされたインデックスを含むさまざまなアドレッシングモードをサポートしますが、PC相対はサポートしません。
レジスタのスタックへの浮動小数点を含みます。
アトミックのための特別なサポート含んでいるリードモディファイライト命令の(xchg、cmpxchg/ cmpxchg8b、xadd、およびと結合した命令整数lockプレフィックス)
SIMD命令(より広いレジスタの隣接セルにエンコードされた多くのオペランドで並列同時単一命令を実行する命令)。

スタック命令
x86アーキテクチャは、実行スタックメカニズムのハードウェアサポートを備えています。以下のような手順push、pop、callおよびret、パラメータを渡すためにローカルデータのためのスペースを割り当てるために、およびコール・リターン・ポイントを保存し、復元するために適切に設定スタックで使用されています。ret サイズの命令は、スペース(高速で)効率的に実装するために非常に有用である呼び出し規則呼び出し先がパラメータによって占有されたスタック領域を再生する責任が
再帰的プロシージャのローカルデータを保持するようにスタックフレームを設定する場合、いくつかの選択肢が高レベル命令(80186で導入)は、procedure-nesting-depth引数とローカルサイズ引数を取り、レジスタのより明示的な操作(;;など)よりも高速な場合が あり ます。速いか遅いかは、特定のx86プロセッサの実装と、コンパイラ、プログラマ、または特定のプログラムコードで使用される呼び出し規約によって異なります。ほとんどのx86コードは、複数のメーカーのx86プロセッサ、およびさまざまな技術世代のプロセッサで実行することを目的としています。これは、さまざまなマイクロアーキテクチャとマイクロコードソリューション、およびさまざまなゲートレベルとトランジスタレベルの設計の選択を意味します。enterpush bpmov bp, spsub sp, size(含むモードアドレッシングのフルレンジ即時およびベース+オフセットさえような命令の場合)pushとはpop、のスタックの直接使用なる整数、浮動小数点およびアドレスデータ簡単、ならびに維持ABIの比較的単純に比較仕様およびメカニズムを一部のRISCアーキテクチャ(より明示的なコールスタックの詳細が必要)。

整数ALU命令
x86のアセンブリ標準的な数学演算を持っている、add、sub、mul、とidiv。論理演算子 and、or、xor、neg、ビットシフト算術および論理、sal/ sar、shl/ shr; 回転キャリー付きとすることなく、rcl/ rcr、rol/ ror、の補数BCD演算命令、aaa、aad、daaなどが挙げられます。

浮動小数点命令
x86アセンブリ言語には、スタックベースの浮動小数点ユニット(FPU)の命令が含まれています。FPUは、8086から80386までのオプションの個別のコプロセッサーであり、80486シリーズのオンチップオプションであり、Pentium以降の80486以降のすべてのIntel x86CPUの標準機能です。FPU命令には、加算、減算、否定、乗算、除算、剰余、平方根、整数の切り捨て、分数の切り捨て、および2の累乗によるスケーリングが含まれます。この操作には、2進化10進、32ビット整数、64ビット整数、32ビット浮動小数点、64ビット浮動小数点のいずれかの形式でメモリから値をロードまたは格納できる変換命令も含まれます。ポイントまたは80ビット浮動小数点(ロード時に、値は現在使用されている浮動小数点モードに変換されます)。x86には、正弦、余弦、正接、逆正接、2を底とするべき乗、2を底とする対数、10、またはeを含む多くの超越関数も含まれています。
命令のスタックレジスタのフォーマットにスタックレジスタは、通常又は場所、に相当し、及び(8つのスタックレジスタの一つです、、…、 )。整数と同様に、第1オペランドは、第1ソースオペランドとデスティネーションオペランドの両方です。そして第1の減算又は除算を行う前に、ソースオペランドをスワップとして選抜されるべきです。加算、減算、乗算、除算、格納、および比較の命令には、演算の完了後にスタックの最上位をポップする命令モードが含まれています。したがって、たとえば、計算を実行してから、スタックの最上位から削除します。これにより、のスタックの最上位の結果が作成されます。fop st, st(n)fop st(n), ststst(0)st(n)st(0)st(1)st(7)fsubrfdivrfaddp st(1), stst(1) = st(1) + st(0)st(0)st(1)st(0)

SIMDの説明
最新のx86CPUにはSIMD命令が含まれており、ワイドSIMDレジスタにエンコードされた多くの値に対してほぼ同じ操作を並行して実行します。さまざまな命令テクノロジは、さまざまなレジスタセットでさまざまな演算をサポートしますが、全体として(MMXからSSE4.2まで)、整数または浮動小数点演算の一般的な計算(加算、減算、乗算、シフト、最小化、最大化、比較、除算)が含まれます。または平方根)。だから、例えば、paddw mm0, mm1(で示さ行う4つの並列16ビットw整数)(で示される加算paddの)mm0への値mm1で結果を格納しますmm0。ストリーミングSIMD拡張命令またはSSEには、レジスタの最初の値のみが実際に変更される(SSE2で拡張される)浮動小数点モードも含まれています。いくつかの他の異常な命令には追加された差分絶対値の和(のために使用される動き推定でビデオ圧縮ように行われているように、MPEG)および(ソフトウェアベースのアルファブレンディングとするのに有用な16ビット乗算累算命令デジタルフィルタリング) 。SSE(SSE3以降)および3DNow!拡張機能には、ペアの浮動小数点値を複素数のように扱うための加算および減算命令が含まれています。
これらの命令セットには、レジスタ内で値をシャッフル、挿入、および抽出するための多数の固定サブワード命令も含まれています。さらに、整数レジスタとXMM(SSEで使用)/ FPU(MMXで使用)レジスタ間でデータを移動するための命令が

データ操作手順
x86プロセッサには、イミディエートオフセット付きのメモリ、レジスタ、オフセット付きのレジスタ、オフセット付きまたはオフセットなしのスケーリングされたレジスタ、およびオプションのオフセット付きのレジスタと別のスケーリングされたレジスタをアドレス指定するための複雑なアドレッシングモードも含まれています。したがって、たとえば、セレクタからのオフセットmov eax, [Table + ebx + esi*4]として計算されたアドレスから32ビットのデータをロードし、それをレジスタに格納する単一の命令としてエンコードできます。一般に、x86プロセッサは、動作しているレジスタのサイズに一致するメモリをロードして使用できます。(SIMD命令には、ハーフロード命令も含まれます。)(Table + ebx + esi * 4)dseax
x86命令セットは、文字列のロード、ストア、移動、スキャンと比較命令(含むlods、stos、movs、scasおよびcmps(指定サイズに各操作を実行する)b、8ビットのバイトのために、w16ビット・ワードは、d32ビットのダブルワードのために)その後、増分/減分は、暗黙アドレスレジスタ((DF、方向フラグに応じて)siのためにlods、di用stosとscas、の両方のためにmovs及びcmps)。ロード、ストア、およびスキャン操作の場合、暗黙のターゲット/ソース/比較レジスタはal、axまたはeaxレジスタにあります(サイズによって異なります)。使用される暗黙のセグメントレジスタはds、forsiおよびesfordiです。cxまたはecxレジスタは減分カウンタとして使用され、カウンタが到達が不等式が検出された(スキャンおよび比較のため)は、ゼロ又は場合の動作が停止します。
スタックは、暗黙的にデクリメント(プッシュ)およびインクリメント(ポップ)するスタックポインターを使用して実装されます。16ビットモードでは、この暗黙のスタックポインタはSS:としてアドレス指定され、32ビットモードではSS:であり、64ビットモードではです。スタックポインタのサイズは、デフォルトの幅と一致するように、プロセッサの動作モード(すなわち、16、32、または64ビット)と一致するという仮定の下で、記憶された最後の値に実際ポイントpush/ pop/ call/ret命令を。また、命令含まれるenterとleave予備とのスタックフレームポインタ設定中にスタックの先頭からデータを削除bp/ ebp/をrbp。しかし、直接設定、または加減算sp/ esp/rspので、レジスタはまた、サポートされているenter/leave命令は、一般的に不要です。
関数の先頭にあるこのコード: ebpを プッシュ; 呼び出し元の関数のスタックフレーム(ebp)を保存する mov
ebp 、 esp ; 呼び出し元のスタック サブ esp 、 4 の上に新しいスタックフレームを作成します。この関数のローカル変数に4バイトのスタックスペースを割り当てます
…機能的には次のものと同等です。
入力 4 、 0
スタックを操作するための他の命令には、(E)FLAGSレジスタを格納および取得するためのpushf/popfが含まれます。pusha/popa命令はスタックにしてから全体を整数レジスタ状態を格納および取得します。
SIMDロードまたはストアの値は、SIMDレジスタの隣接する位置にパックされていると想定され、リトルエンディアンの順序で並べられます。一部のSSEロードおよびストア命令は、正しく機能するために16バイトのアラインメントを必要とします。SIMD命令セットには、ロードを実行するが、キャッシュのロードに使用されるレジスタを対象としない「プリフェッチ」命令も含まれています。SSE命令セットには、宛先がまだキャッシュされていない場合にキャッシュ割り当てを実行せずにメモリに直接ストアを実行する非一時ストア命令も含まれています(それ以外の場合は通常のストアのように動作します)。
ほとんどの一般的な整数および浮動小数点(SIMDは除く)命令は、1つのパラメーターを2番目のソースパラメーターとしての複素数アドレスとして使用できます。整数命令は、1つのメモリパラメータをデスティネーションオペランドとして受け入れることもできます。

プログラムフロー
x86アセンブリには、無条件のジャンプ操作がありますjmp。これは、パラメータとしてイミディエートアドレス、レジスタ、または間接アドレスを受け取ることができます(ほとんどのRISCプロセッサは、リンクレジスタまたはジャンプの短いイミディエートディスプレイスメントのみをサポートすることに注意してください)。
またjz、jnz(ゼロにジャンプ)、(ゼロjg以外にジャンプ)、(より大きいにジャンプ、符号付き)、jl(より小さいにジャンプ、符号付き)、ja(上にジャンプ/より大きい、符号なし)を含むいくつかの条件付きジャンプもサポートされています。、jb(下にジャンプ/未満、署名なし)。これらの条件付き演算は、(E)FLAGSレジスタの特定のビットの状態に基づいています。多くの算術演算および論理演算は、結果に応じてこれらのフラグを設定、クリア、または補完します。比較cmp(比較)およびtest命令は、オペランドの値を変更せずに、それぞれ減算またはビット単位のAND演算を実行したかのようにフラグを設定します。clc(クリアキャリーフラグ)やcmc(補完キャリーフラグ)など、フラグを直接操作する命令も浮動小数点の比較は、fcomまたはficom命令を介して実行され、最終的に整数フラグに変換する必要が
各ジャンプ操作には、オペランドのサイズに応じて3つの異なる形式が短いジャンプは現在の命令からの相対オフセットである8ビット符号付きオペランドを使用します。周辺ジャンプは短いジャンプと同様であるが、16ビット符号付きオペランド(実際またはプロテクトモードの場合)または32ビット符号付きオペランド(32ビット保護モードでのみ)を使用します。遠絶対アドレスとしてオフセット値:ジャンプは、フルセグメント・ベースを使用するものです。これらのそれぞれには、間接的なインデックス形式も
単純なジャンプ操作に加えて、(サブルーチンを呼び出す)命令callとret(サブルーチンから戻る)命令が制御をサブルーチンに移す前callに、に続く命令のセグメントオフセットアドレスをcallスタックにプッシュします。retこの値をスタックからポップしてジャンプし、プログラムのその部分に制御フローを効果的に戻します。の場合far call、セグメントベースはオフセットに続いてプッシュされます。far retオフセットをポップしてから、セグメントベースをポップして返します。
現在の(E)FLAGSレジスタ値をスタックに保存してからを実行する2つの同様の命令int(interrupt)もありますが、アドレスの代わりに、割り込みベクトル、割り込みハンドラのテーブルへのインデックスを使用する点が異なります。アドレス。通常、割り込みハンドラは、操作の結果を呼び出し側プログラムに返すために使用されない限り、使用する他のすべてのCPUレジスタを保存します(割り込みと呼ばれるソフトウェアで)。割り込み命令からの一致するリターンは、リターン後にフラグを復元するです。上記のタイプのソフト割り込みは、一部のオペレーティングシステムでシステムコールに使用され、ハード割り込みハンドラーのデバッグにも使用できます。ハード割り込みは外部ハードウェアイベントによってトリガーされ、現在実行中のプログラムの状態が不明であるため、すべてのレジスタ値を保持する必要がプロテクトモードでは、OSによって割り込みが設定され、タスクスイッチがトリガーされます。これにより、アクティブなタスクのすべてのレジスタが自動的に保存されます。far calliret

“こんにちは世界!” MASMスタイルのアセンブリでDOS用のプログラム
出力に割り込み21hを使用–他のサンプルはlibcのprintfを使用してstdoutに出力します。
.model small .stack 100h.dataのMSG デシベル ‘こんにちは、世界!$’.code start: mov ah 、 09h ; メッセージ表示 のLEA DXを、 MSG INT 21H MOV 斧、 4C00h 。実行終了 int型 21Hを終了 開始

“こんにちは世界!” MASMスタイルのアセンブリでWindows用のプログラム
; 必要と/ 6.15およびそれ以前のバージョンのCOFFスイッチ.386 .MODELの 小さなを、C .STACK 1000H.data msg
db “Hello world!” 、0.code includelib libcmt.lib includelib libvcruntime.lib includelib libucrt.lib includelib legend_stdio_definitions.libEXTRN のprintf :近くEXTRNの 終了:近くpublic main main proc
push offset msgcall printf push 0
call exit main endp終わり

“こんにちは世界!” NASMスタイルのアセンブリでのWindows用プログラム
; イメージベース= 0x00400000 %define RVA(x)(x-0x00400000)セクション.text push dword hello call dword push byte + 0 call dword retセクション.dataのハロー デシベル の”Hello World!”セクション.idata DD RVA (msvcrt_LookupTable )DD – 1 DD 0 DD RVA (msvcrt_string )DD RVA (msvcrt_imports )回 5は ddは 0 。記述子テーブルを終了しますmsvcrt_string dd “msvcrt.dll” 、 0 msvcrt_LookupTable:dd RVA (msvcrt_printf )dd RVA (msvcrt_exit )dd 0msvcrt_imports:printf dd RVA (msvcrt_printf )exit dd RVA (msvcrt_exit )dd 0msvcrt_printf:dw 1 dw “printf” 、 0 msvcrt_exit:dw 2 dw “exit” 、 0 dd 0

“こんにちは世界!” NASMスタイルのアセンブリでのLinux用プログラム
; ; このプログラムは、32ビットプロテクトモードで実行されます。; ビルド:nasm -f elf -F stabs name.asm ; リンク:ld -o name name.o ; ; 64ビットロングモードでは、64ビットレジスタを使用できます(たとえば、eaxの代わりにrax、ebxの代わりにrbxなど)。また、ビルドコマンドで「-feld64」の「-feld」を変更します。; セクション.data
; 初期化されたデータのセクションstr: db’Hello world! ‘ 、 0Ah
; 終了(10進)で新しい行の文字でメッセージ文字列str_len: EQU $ – STR
。strの開始アドレスを引くことにより、文字列の長さ(バイト)を計算します
。このアドレスから($記号)セクション.text
; これは、コードセクションでグローバル_start
。_startはエントリポイントであり、
;がグローバルスコープを「見る」必要がリンカ-C / C ++のmain()と同等_start :
; _start手順の定義は、ここから始まります のmov eaxに、 4
。sys_write関数コードを(OSベクトルテーブルから)指定します mov ebx 、 1
; ファイル記述子stdoutを指定します–gnu / linuxでは、すべてがファイルとして扱われます
; でも、ハードウェアデバイス のMOV ECX 、 STR
。ECXレジスタに文字列メッセージの移動開始_address_ のMOV EDX 、 str_len 。メッセージの長さ(バイト単位)の移動 int 80h
; カーネルに割り込み、設定したシステムコールを実行します-
; gnu / linuxでは、サービスはカーネル mov eax 、 1を
介して要求されます。sys_exit関数コードを指定します(OSベクトルテーブルから) mov ebx 、 0
; OSのリターンコードを指定します(ゼロはOSにすべてがうまくいったことを示します) int 80h
; カーネルに割り込み、システムコールを実行します(終了します)

“こんにちは世界!” C標準ライブラリを使用したNASMスタイルのアセンブリでのLinux用プログラム
; ; このプログラムは、32ビットプロテクトモードで実行されます。; gccはデフォルトで標準Cライブラリをリンクします; ビルド:nasm -f elf -F stabs name.asm ; リンク:gcc -o name name.o ; ; 64ビットロングモードでは、64ビットレジスタを使用できます(たとえば、eaxの代わりにrax、ebxの代わりにrbxなど)。また、ビルドコマンドで「-feld64」の「-feld」を変更します。;
グローバル main
; mainは、C標準ライブラリ extern printf に対してコンパイルされるものとして定義する必要があります; printfが別のオブジェクトモジュールで宣言されているため、外部シンボルの使用を宣言します。
;リンカーは後でこのシンボルを解決します。セグメント.DATA
;初期化データ用のセクション の文字列 デシベル 「こんにちは世界!」、 0Ah 、 0h
;改行文字(10進数の10)とNULLターミネータを含むメッセージ文字列
; stringは、「Hello、World」が格納されている開始アドレスを参照するようになりました。セグメントの.textメイン:
プッシュ 文字列は
、スタック上に文字列の最初の文字のアドレスを押してこれはprintfの引数になり
、コール のprintf
;呼び出しがprintfの
追加 ESP 、 4
;プッシュ文字列引数洗い流す4によって進歩スタック・ポインタ RETを ;リターン

“こんにちは世界!” NASMスタイルのアセンブリでの64ビットモードLinux用のプログラム
; ビルド:nasm -f elf64 -F dwarf hello.asm ; リンク:ld -o hello hello.oデフォルトの REL ; デフォルトではRIP相対アドレッシングモードを使用するため、 = セクション.rodata ; 読み取り専用データは、GNU / Linuxの.rodataセクションに入れることができます。たとえば、Windows Helloの .rdata :db “Hello world!” 、10
; 10 = ` n`。len_Hello: equ $ -こんにちは
; NASMに長さをアセンブル時定数として計算させる;; write()は長さを取るため、0で終了するCスタイルの文字列は必要ありません。それはプットのためになりますセクション.textglobal _start _start: mov eax 、 1 ; Linuxからの__NR_writeシステムコール番号asm / unistd_64.h(x86_64) mov edi 、 1 ; int fd = STDOUT_FILENO lea rsi 、 ; x86-64の用途は、RIP-相対LEAをREGSに静的アドレスを入れて MOV RDX 、 len_Helloを 。size_t count = len_Hello syscall ; write(1、Hello、len_Hello); カーネルを呼び出して、実際にシステムコールを実行します ;; RAXでの戻り値。RCXとR11もsyscallによって上書きされます mov eax 、 60 ; __NR_exit呼び出し番号(x86_64) xor edi 、 edi ; status = 0(通常どおり終了) syscall ; _exit(0)
それを実行するstraceと、プロセスで余分なシステムコールが行われないことが確認されます。printfバージョンは、libcを初期化し、ダイナミックリンクを実行するためにさらに多くのシステムコールを行います。ただし、-pieまたは共有ライブラリを使用せずにldを使用してリンクしたため、これは静的実行可能ファイルです。ユーザースペースで実行される唯一の命令は、あなたが提供するものです。
$ strace ./hello> / dev / null
#リダイレクトなしの場合、プログラムのstdoutは混合straceのstderrへのロギングです。これは通常は問題ありませんexecve( “./ hello”、[“./ hello”]、0x7ffc8b0b3570 / * 51 vars * /)= 0 write(1、 “Hello world! n”、13)= 13 exit(0) =?+++は0で終了しました+++

フラグレジスタの使用
フラグは、x86アーキテクチャでの比較に頻繁に使用されます。2つのデータ間で比較が行われると、CPUは関連する1つまたは複数のフラグを設定します。これに続いて、条件付きジャンプ命令を使用して、フラグをチェックし、実行する必要のあるコードに分岐できます。例:
cmp eax 、 ebx jne do_something ; … do_something : ; ここで何かをする
フラグは、特定の機能または実行モードをオンまたはオフにするためにx86アーキテクチャでも使用されます。たとえば、マスク可能なすべての割り込みを無効にするには、次の命令を使用できます。 cli フラグレジスタにも直接アクセスできます。フラグレジスタの下位8ビットはah、lahf命令を使用してロードできます。全体フラグも命令を使用してスタックオンとオフに移動させることができるレジスタpushf、popf、int(を含むinto)とiret。

命令ポインタレジスタの使用
命令ポインタと呼ばれるip、16ビットモードでeip32ビットモードで、そしてrip64ビットモードです。命令ポインタレジスタは、プロセッサが次に実行を試みるメモリアドレスを指します。そのまま16ビットまたは32ビットモードでアクセスすることはできないが、以下のような配列は、アドレス入れて書き込むことができるnext_lineにはeax:
コール next_line next_line: ポップ EAX
この一連の命令は、次の命令(この場合は0)からのターゲット命令のオフセットをバイト単位で記述する命令ポインター相対即値オペランドをとるため、位置に依存しないコードを生成callします。
命令ポインタへの書き込みは簡単です-jmp命令はそう、たとえば、以下のようなシーケンスは内容置く、ターゲットアドレスに命令ポインタをセットeaxにしeip:
jmp eax
64ビットモードでは、命令は命令ポインタに関連するデータを参照できるため、命令ポインタの値を別のレジスタにコピーする必要が少なくなります。

も参照してください X86命令リスト
X86アーキテクチャ
CPU設計
アセンブラのリスト
自己修正コード
DOS

参考文献
^ 「Intel8008(i8008)マイクロプロセッサフ​​ァミリ」。www.cpu-world.com 。2021-03-25を取得。
^ 「Intel8008」。CPUMUSEUM-マイクロプロセッサとダイの写真の博物館。2021-03-25を取得。
^ “インテル8008 OPCODES” 。www.pastraiser.com 。2021-03-25を取得。
^ Narayam、Ram(2007-10-17)。「Linuxアセンブラ:GASとNASMの比較」。2013年10月3日にオリジナルからアーカイブされました。
^ 「Unixの作成」。2014年4月2日にオリジナルからアーカイブされました。
^ ハイド、ランドール。「どのアセンブラーが最適ですか?」。
^ 「GNUアセンブラニュース、v2.1はIntel構文をサポートします」。2008-04-04 。
^ 「i386-バグ(asを使用)」。Binutilsのドキュメント。
^ ミューラー、スコット(2006年3月24日)。「P2(286)第2世代プロセッサ」。PCのアップグレードと修復、第17版(本)(17版)。キュー。ISBN
 0-7897-3404-4。
^ 「私はちょうどアセンブリを始めました」。daniweb.com。2008年。

参考文献

マニュアル
Intel64およびIA-32ソフトウェア開発者マニュアル
AMD64アーキテクチャプログラマーズマニュアル(第1巻から第5巻)


エド、ジョーゲンセン。Ubuntuを使用したx86-64アセンブリ言語プログラミング (PDF)(1.0.97 ed。)NS。367。
Dennis Yurichev:アセンブリ言語を理解する

外部リンク
ウィキブックスには、x86アセンブリのトピックに関する本が