ARM アセンブリ言語 (2)

ARMアセンブリ言語

I.はじめに

ARM アセンブリ言語は、低レベルのコンピュータ命令セット アーキテクチャ (ISA) 言語であり、ARM プロセッサ上の命令セット アーキテクチャであり、オペレーティング システム、ドライバ、組み込みシステム アプリケーション プログラムなどの低レベルのシステム ソフトウェアを作成するために使用されます。

ARM アセンブリ言語はレジスタベースの命令セットを使用しており、命令が操作するデータは通常、メモリではなくプロセッサのレジスタに格納されます。ARM アセンブリ言語は、アセンブリ命令を使用して、データ転送、算術論理演算、分岐およびジャンプ命令などのコンピュータの動作を制御します。

ARM アセンブリ言語の構文は通常、シンプルで直感的であり、他のアセンブリ言語と似ていますが、特定の構文規則は ARM プロセッサ モデルによって異なります。ARM アセンブリ言語コードを記述するには、基礎となるコンピューター ハードウェアと命令セット アーキテクチャがどのように動作するかをしっかりと理解する必要があります。

2 番目に、ARM プロセッサのアドレッシング モード

1. レジスタのアドレス指定

あるレジスタの値を別のレジスタに転送する操作。

MOV R1,R2      ;R2→R1,将寄存器R2的值传送到寄存器R1

命令が実行されると、レジスタ内の値が直接フェッチされて操作されます。

2. 即時アドレス指定

即時アドレッシング モードの目的は、オペランドをオペコードの直後に配置し、オペコードとともに命令コード セグメントに配置することです。プログラムの実行中、プログラムは他のアドレス ユニットにフェッチすることなくオペランドを直接呼び出します。対応するオペランド、命令内に記述される上記のオペランドを即値ともいいます。
MOV R0、#0x1234
MOV はオペコード、R0 は最初のオペランド、0x1234 は即値です

イミディエイト (イミディエイト) は、命令で直接指定されたデータ値を指します。これは、偶数ビットを右に循環シフトすることによって得られる 8 ビット定数に対応する必要があります。イミディエイト データは、通常、命令内の定数、アドレス、およびオフセットに使用されます。

即時値が正当であるかどうかを判断し、迅速に判断する方法:

  • (1) まず、この数値を 2 進数で表し、数値内の「1」の最大間隔が 8 (先頭と末尾の 2 つの 1 を含む) より大きいかどうかを確認します。 8 より大きい場合、この数値は不正である必要があります。1 回 8 以下であれば、合法である可能性があります。
    例:
    0x1101 のバイナリは次のとおりです: 0000 0000 0000 0000 000 1 0001 0000 0001途中で見ても、ループ内で見ても、2 つの 1 の間の最大間隔は 8 より大きいため、即時番号。

  • (2) 方法 1:
    2 つの 1 の間の最大間隔が 8 より大きい場合、それは即値であってはなりません。
    順番に見たときに 1 の最大間隔が 8 に等しい場合、この時点で、この番号の最上位桁の 1 の前または最下位桁の 1 の後ろに偶数個の 0 があるかどうかを確認できます。は 1 つのケースであり、この数字は合法です。
    ループ表示時に最大間隔 1 が 8 以下であれば、この時点で確認できます。ループ表示時に両端で求めた間隔のどちらかが偶数かどうかを確認できます。偶数の場合、この数値は有効です。

  • (3) 方法 2:
    1. データをバイナリ形式に変換し、下位から上位まで 4 桁ずつ書き込み、上位 4 桁で足りない場合は上位の前に 0 を追加します。注文。
    2. 1 という数字が 8 より大きい場合は、明らかに即値ではありません。8 以下の場合は、次の手順に進みます。
    3. データの途中に 24 以上の 0 が連続する場合、上位ビットがすべて 0 になるようにサイクルを 4 の倍数左にシフトします。
    4. 上位の 1 を見つけ、その前の偶数の 0 を削除します。
    5. 下位の 1 を見つけて、次に大きい偶数の 0 を削除します。
    6. 残りの桁を数えます。8 桁以下の場合、この数値は即値です。そうでない場合は、即値ではありません。

概要: 即値を判断する場合は、まず 2 進数に変換し、次に 8 桁の数値を取り、偶数ビットを左右に移動して復元できるかどうかを確認します。
例:
1. 0X20000018 が即値かどうかを判断するには、
データをバイナリ0010 0000 0000 0000 0000 0000 000 1 1000に変換し、32-3=29 回右回転して元の数値を取得します。したがって、これは即値ではありません。 。
2. 0x104 が即値かどうかを判断します。
データをバイナリ0000 0000 0000 0000 0000 000 1 0000 01 00に変換します。 01000001を取得し、元の数値を取得するために 32-2=30 回サイクルする場合、 10000010を取得する場合は、サイクル32-1=31 回で元の数値が得られます。

ARM アセンブリ言語では、即値はプレフィックス "#" で表すことができ、"0x" は 16 進値を表すために使用されます。"#" の後には正当な即値が続く必要があることに注意してください。たとえば、次のコマンドでは次のようになります。

ADD R0, R0, #10   ;R0+10→R0 ,将立即数10加到寄存器R0中
MOV R0,#0x1234   ;0x1234→R0

3. レジスタシフトアドレッシング

3.1 LSL: 論理左シフト

MOV R0,#0xff0000f0    ;#0xff0000f0 →R0
MOV R0,R0,LSL #4     ;R0+R*2^4→R0

例: 0xff0000f0 は4 ビットの論理左シフト後の0xf0000f00であり、キャリー出力は 0xf です。
レジスタ内のワードの下位端の空いたビットは 0 で埋められます。

3.2 LSR: 論理右シフト

MOV R0,R0,LSR #4     ;R0+R/2^4→R0

例: 0xff0000f0 は4 ビットの論理右シフト後の0x0ff0000fであり、キャリー出力は 0x0 です。
レジスタ内のワードの上位の空いたビットは 0 で埋められます。

3.3 ASR: 算術右シフト

MOV R0,R0,ASR #4     ;R0+R/2^4→R0

例: 0xff0000f0 は4 ビット算術右シフト後の0xfff0000fであり、キャリー出力は 0x0 です。
シフト プロセス中は符号ビット (最上位ビット) を変更しないでください。つまり、ソース オペランドが正の数であり、ワードの上位の空きは 0 で埋められ、それ以外の場合は 1 で埋められます。

3.4 ROR: 右回転

MOV R0,R0,ROR #4     ;R0+R/2^4→R0

例: 0xff0000f0 は、 4 ビット循環右シフト後の0x0ff0000fであり、キャリー出力は 0x0 です。
ワードの下位端からシフトされたビットは、上位端の空いたビットを埋めます。

4. 間接アドレス指定を登録する

レジスタはオペランドのアドレス ポインタであり、オペランドはメモリに格納されます。

LDR   R0,[R1]   ;[R1]→R0    取
STR   R0,[R1]    ;R0→[R1]    存

最初の命令は値が R1 であるメモリのデータを R0 に転送し、2 番目の命令は R0 の値をアドレスが R1 であるメモリに転送します。
LDR は、次のような疑似命令としても使用できます。

LDR r0, =0xFFF0 @伪指令
LDR r0, 0xFFFF @指令

つまり、任意の数値を直接渡すことができ、コンパイル時にロード命令として解析されるため、即値を気にする必要がありません。

5. ベースアドレスとオフセットのアドレス指定

レジスタの内容を命令で指定されたアドレス オフセットに加算して、オペランドの実効アドレスを取得します。通常、ベース アドレスに近いアドレスにあるユニットにアクセスするために使用されます。
(1) フロントインデックスモード
LDR R0,[R1,#4] ;[R1+4]→R0
(2) 自動インデックスモード
LDR R0,[R1,#4]! ;[R1+4]→R0, R1+ 4→R1、「!」はアドレス更新
後のインデックスモードLDR (3)
R0,[R1],#4 ;[R1]→R0,R1+4→R1

おすすめ

転載: blog.csdn.net/weixin_57038791/article/details/130454384