3

まず、「AT&T と Intel のどちらのアセンブリを使用していますか?」という質問に悩まないでください。またはそのようなもの。

or命令を使用せずADDADCに、AX と BX などの 2 つのレジスタの内容を一緒に追加できるかどうか疑問に思っています。この一連の指示のみを使用してそれを行いたい:

MOV
CMP
JMP
JE
JNE

実際のコードのない単なるアルゴリズム、またはこれに関する優れたチュートリアルであっても、簡単な例を見たいと思います。

なぜ私がこれを尋ねているのか疑問に思っているなら、それは私が非常に基本的なコンピュータを作成していて、今のところこれらの命令のみを提供しているためです.2つのレジスタを一緒に追加できるかどうかを知りたい.

4

3 に答える 3

3

編集:任意の加算または減算は、258 バイトのルックアップ テーブルmovで、cmpおよびのみを使用して行うことができますjne巨大なルックアップ テーブルはまったく必要ありません。下位 8 ビットと上位 8 ビットは、同じルックアップ テーブルを使用して個別に更新されます。

以下は、 258 バイトのルックアップ テーブルを 1 つだけ使用し、 と のみを合計axして使用するコードです。bxmovcmpjne

[ビット 64]

; 有効な命令: mov、cmp、jmp、je、jne
; 使用命令: mov、cmp、jne

セクション .text
グローバル_開始

; このコードはaxとbxを合計します

_始める:

; 合計する値を定義します (ax & bx)。

        移動斧、12853; 加数 1 の例。
        mov bx,33276 ; 加数 2 の例。

; 合計は簡単です: ゼロになるまで各被加数を減らすだけです。
; 減分ごとに、合計を (ax で) 増分します。

        cmp bx,0
        jne start_summing ; 通常、これは準備ができており、
                                ; 次の 2 つの命令が削除されます。

                cmp bx,1 ; これは、jne で十分であることを示しています。
                準備ができました。この条件付きジャンプは常に分岐します。

start_summing:
        移動 ecx,0

summing_loop:
        mov cl,bl
        mov bl,[rcx+(number_line-1)] ; bl を減少させます。
        cmp bl,255
        jne bl_not_carry

                mov cl,bh
                mov bh,[rcx+(number_line-1)] ; デクリメント bh。

bl_not_carry:
        mov cl,al
        mov al,[rcx+(number_line+1)] ; インクリメントアル。
        cmp al,0
        jne al_not_carry

                mov cl,ah
                mov ah,[rcx+(number_line+1)] ; インクリメントああ。

al_not_carry:
        cmp bx,0
        jne summing_loop

準備:

; sum は eax になりました。

セクション .data

max_value eq 255
max_value_plus_1 式 (最大値 + 1)

デシベル最大値; 0 - 1 = 255

行番号:

%assign myValue 0

%rep max_value_plus_1
        デシベル myValue
        %assign myValue (myValue + 1)
%endrep

デシベル 0

編集:答えの残りの部分は、より多くのメモリを必要とする他のソリューションを扱います。

編集: 16 ビット オペランドの加算または減算には、1 次元の 128 KiB ルックアップ テーブルで十分です。巨大なルックアップ テーブルは必要ありません。 編集:通常はキャリー フラグを設定する加算が誤った結果を生成する原因となるバグを修正しました。

これはx86-64アセンブリのコードで、YASMでアセンブルされ、おそらくNASMでもアセンブルされます。&add ax,bxのみを使用して をmov実装します。cmpjne

[ビット 64]

; 有効なコマンド: mov、cmp、jmp、je、jne
; 使用コマンド:mov、cmp、jne

セクション .text
グローバル_開始

; このコードはaxとbxを合計します

_始める:

; 合計する値を定義します (ax & bx)。

        移動斧、12853; 加数 1 の例。
        mov bx,33276 ; 加数 2 の例。

; 合計は簡単です: ゼロになるまで各被加数を減らすだけです。
; 減分ごとに、合計を (ax で) 増分します。

        移動edx,0
        移動DX、斧
        eax、edxを移動します。eax = 斧

        移動 ecx,0
        mov cx,bx ; ecx = bx

summing_loop:
        mov cx,[2*rcx+(number_line-2)] ; ecx をデクリメントします。
        mov ax,[2*rax+(number_line+2)] ; eax をインクリメントします。
        cmp ecx,0
        jne summing_loop

; sum は eax になりました。

セクション .data

max_value eq 65535

dw max_value ; 0 - 1 = 65535

行番号:

%assign myValue 0

%rep max_value
        dw myValue
        %assign myValue (myValue + 1)
%endrep

dw 0

編集:回答の残りの部分は、私が最初に思いついたより限定的なソリューションを扱っています。

これは、2 次元ルックアップ テーブルで実行できます。

al&などの 8 ビット レジスタの場合はbl簡単です。16 ビット レジスタの場合は可能ですが、ルックアップ テーブルが巨大になります (ほぼ 1 テビバイト)。以下の理由を参照してください。ルックアップ テーブルの各セルには、対応する X 座標と Y 座標の合計が含まれます (X 座標と Y 座標は被加数です)。

8 ビットの合計の場合、ルックアップ テーブル(256 * 256 行列)は次のようになります。

db   0,   1,   2, ... , 253, 254, 255
db   1,   2,   3, ... , 254, 255,   0
db   2,   3,   4, ... , 255,   0,   1
     .    .    .  .       .    .    .
     .    .    .   .      .    .    .
     .    .    .    .     .    .    .
db 253, 254, 255, ... , 250, 251, 252
db 254, 255,   0, ... , 251, 252, 253
db 255,   0,   1, ... , 252, 253, 254

x86 および x86-64 では、mov256^n による乗算に使用できます。つまり、256、65536、16777216、...

で 256 を掛けるのmovは簡単で、計算は次のax = 256 * blとおりです。

mov ax,0
mov ah,bl

例を追加するには。al& bl、正しいオフセットを取得する必要があります。それは256 * al + bl、 or256 * bl + alです (ルックアップ テーブルは対称行列であり、加算は可換演算であるため対称であるため)。

x86/x86-64のみを使用して 65536 以上の数を掛けるmovには、メモリを使用する必要があります。これは、32 ビット汎用レジスタ (eax など) の上位 16 ビットまたは 64 レジスタの上位 32 ビットを直接アドレス指定する方法がないためです。ビット汎用レジスタ (rax など)。

eax = 65536 * bxのみを使用して計算するにはmov:

mov [temp], dword 0
mov [temp+2], bx
mov eax, [temp]

...

temp dd 0

しかし、16 ビット値の実際の問題は、x86/x86-64 では、メモリが word/dword/qword オフセットではなくバイト オフセットを使用してアドレス指定され、 256^nでしか乗算できないことです。しかし、最初に、乗算とバイト オフセット アドレッシングでこの問題がなければ、ルックアップ テーブルがどのようになるかを見てみましょう。ルックアップ テーブルは次のようになります。

dw     0,     1,     2, ... , 65533, 65534, 65535
dw     1,     2,     3, ... , 65534, 65535,     0
dw     2,     3,     4, ... , 65535,     0,     1
       .      .      .  .         .      .      .
       .      .      .   .        .      .      .
       .      .      .    .       .      .      .
dw 65533, 65534, 65535, ... , 65530, 65531, 65532
dw 65534, 65535,     0, ... , 65531, 65532, 65533
dw 65535,     0,     1, ... , 65532, 65533, 65534

ここでは、各行に 65536 個のセルがあり、それぞれが dword なので、各行は 2 * 65536 バイト = 131072 バイトになります。65536 行あるので、65536 * 65536 の行列です。

x86 アセンブリでは 1、2、4 、および 8 のスケール係数が許可されるため、ワード サイズのセルは X (水平インデックス、被加数のいずれか) では問題になりません。

編集:配列サイズに関するテキストを修正しました。実際には 1 TiB より少し小さいです。

ここでの問題は、Y (垂直方向のインデックス、もう一方の被加数) を 131072 だけで乗算することができないことmovです。したがって、ルックアップ テーブルの各行を 32768 回繰り返す必要があります。より正確には、実際のデータ行の間に 32767 の未使用のフィラー行が必要です。なぜ 32767 なのですか?は 256、65536、16777216 の乗算にのみ使用できるためmov、Y (垂直インデックス、もう一方の被加数) に 16777216 を乗算する必要があります。各行は 131072 バイトかかるため、新しいデータ行を作成するには、16777216 バイトごとに、各データ行の後に 32767 の未使用のフィラー行 (それぞれ 131072 バイト) が必要です。最後のデータ行の後、フィラー行は必要ないため、配列の合計サイズは次のようになります。

65535 * 16777216 + 131072 = 10.99 * 10^12 バイト = ほぼ 1 テビバイト (1 TiB)

残念ながら、私のコンピューターにはそれほど多くのメモリがありませんが、x86-64 では可能です。

mov以下は、256 * 256 ルックアップ テーブルのみを使用した 8 ビット加算のコードです(YASM でテスト済み、NASM でアセンブルする必要があります)。

[ビット 64]

; 有効な命令: mov、cmp、jmp、je、jne
; 使用命令: mov

セクション .text
グローバル_開始

; al & bl は保存する必要があります

; このコードは al と bl を合計します

_始める:

; 合計する値を定義します (al & bl)。

        動く47。例の最初の加数
        移動 bl,55 ; 例 2 番目の被加数

; 加算コードはここから始まります。

        移動 ecx,0
        mov cl,al ; ecx = アル
        mov ch,bl ; ecx = 256 * bl + アル
        mov al,[rcx+sum_look_up_table] ; ルックアップ テーブルから合計を取得します。
                                           ; 32 ビット コードの場合、rcx -> ecx
; 合計は al になりました。

セクション .data

y_times equ 256
x_times equ 256

sum_look_up_table:

%assign myY 0

%rep y_times
        %assign myX 0

        %rep x_times
                %assign myValue (myX + myY)
                %rep y_times
                        %if myValue >= 256
                                %assign myValue (myValue - 256)
                        %endif
                %endrep
                デシベル myValue
                %assign myX (myX + 1)
        %endrep

        %assign myY (myY + 1)
%endrep
于 2013-04-11T22:47:52.377 に答える
3

理論的には、そうです。次の巨大なプログラムは、命令セットを使用して表現でき、加算を実行します。

if ax = 0 and bx = 0:
  result = 0
else if ax = 0 and bx = 1:
  result = 1
...
else if ax = 42 and bx = 24:
  result = 66
...

実際の意味では、あなたの質問に対する答えは「いいえ」です。

于 2013-04-10T09:19:19.407 に答える
2

現時点ではこれらの命令のみを提供する非常に基本的なコンピューターを作成しているため、2 つのレジスタを一緒に追加できるかどうかを知りたいと考えています。

この場合、アセンブリ言語が有用であると見なされるために必要な最小命令セットは何ですか?を読む必要があります。

要するに、最小限の可能なアーキテクチャには1 つの命令しかありません。しかし、より便利にするには、非常に基本的なコンピューターに少なくとも 1 つのビット操作命令が必要です。すべての論理計算には、 1 つのNANDorNORだけで十分です。これにより、算術演算も実行できますが、個別の ADD/SUB ほど効率的ではありません。さらに、別の条件付きジャンプが必要です。合計で 3 つの命令になります。しかし、そのような指示が 5 つある場合は、他の質問で読むことができるより良い指示の選択肢がたくさんあります。

そうは言っても、チューリング完全であることが証明されているためMOV、x86 だけでなく、 8051のような他の多くのアーキテクチャでも何でも実行できます。有効な C コードを MOV のみ (または XOR、SUB、ADD、XADD、ADC、SBB、AND/OR、PUSH/POP、1 ビット シフト、または CMPXCHG/XCHG のいずれかのみ) のプログラムにコンパイルするコンパイラもあります。movfuscatorという名前です。コンパイラがどのように機能するかについての詳細は、Break Me00 The MoVfuscator Turning mov into soul crushing RE の悪夢 Christopher Domasで説明されています。時間がない場合は、スライドを読んでください。基本的に、ほとんどの目的でルックアップ テーブルを使用します。これは、 8 ビットの加算がどのように達成されるかの例です。

static void alu_add8(char* s, char* x, char* y, char* c, int off)
{
    /* requires dword carry initialized */
    print("# alu_add8\n");
    debug_id();
    print("movl $0, %%eax\n");
    print("movl $0, %%ebx\n");
    print("movl $0, %%ecx\n");
    print("movl $0, %%edx\n");
    print("movb (%s+%d), %%al\n", x, off);
    print("movb (%s+%d), %%cl\n", y, off);
    print("movl (%s), %%ebx\n", c);
    print("movb alu_add8l(%%eax,%%ecx), %%dl\n");
    print("movb alu_add8h(%%eax,%%ecx), %%dh\n");
    print("movb alu_add8l(%%edx,%%ebx), %%al\n");
    print("movb %%al, (%s+%d)\n", s, off);
    print("movb alu_add8h(%%edx,%%ebx), %%al\n");
    print("movb %%al, (%s)\n", c);
    print("# end alu_add8\n");
}

参考文献

于 2013-08-03T01:01:25.943 に答える