Assembly 如何将两个寄存器添加到一起而不使用;加上「;指示

Assembly 如何将两个寄存器添加到一起而不使用;加上「;指示,assembly,x86,add,Assembly,X86,Add,首先,不要为“你用的是AT&t还是英特尔汇编?”之类的问题而烦恼 我想知道是否可以在不使用add或ADC指令的情况下将两个寄存器(如AX和BX)的内容一起添加。我只想使用以下一组说明: MOV CMP JMP JE JNE 我想看一个简单的例子,即使它只是算法,没有任何实际代码,或者是一个很好的教程 如果你想知道我为什么问这个问题,那是因为我正在创建一台非常基本的计算机,目前只提供这些指令,我想知道它是否已经能够将两个寄存器添加到一起。理论上,是的。以下大型程序可以使用您的指令集表示,并将执行

首先,不要为“你用的是AT&t还是英特尔汇编?”之类的问题而烦恼

我想知道是否可以在不使用
add
ADC
指令的情况下将两个寄存器(如AX和BX)的内容一起添加。我只想使用以下一组说明:

MOV
CMP
JMP
JE
JNE
我想看一个简单的例子,即使它只是算法,没有任何实际代码,或者是一个很好的教程


如果你想知道我为什么问这个问题,那是因为我正在创建一台非常基本的计算机,目前只提供这些指令,我想知道它是否已经能够将两个寄存器添加到一起。

理论上,是的。以下大型程序可以使用您的指令集表示,并将执行加法:

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
...

在任何实际意义上,您的问题的答案都是“否”。

编辑:任何加法或减法都可以使用258字节的查找表,并且只使用
mov
cmp
jne
。绝对没有必要使用巨型查找表。低8位和高8位使用相同的查找表分别更新

这里的代码只使用一个258字节的查找表,并且只使用
mov
cmp
jne
ax
bx
进行求和:

[bits 64] ; valid instuctions: mov, cmp, jmp, je, jne ; used instuctions: mov, cmp, jne section .text global _start ; this code sums ax & bx _start: ; define the values to be summed (in ax & bx). mov ax,12853 ; example summand 1. mov bx,33276 ; example summand 2. ; summing is easy: just decrement each summand until it becomes zero, ; and for each decrement, increment the sum (in ax). cmp bx,0 jne start_summing ; normally this would be je ready and ; next 2 instructions would be deleted. cmp bx,1 ; this shows that jne is sufficient. jne ready ; this conditional jump branches always. start_summing: mov ecx,0 summing_loop: mov cl,bl mov bl,[rcx+(number_line-1)] ; decrement bl. cmp bl,255 jne bl_not_carry mov cl,bh mov bh,[rcx+(number_line-1)] ; decrement bh. bl_not_carry: mov cl,al mov al,[rcx+(number_line+1)] ; increment al. cmp al,0 jne al_not_carry mov cl,ah mov ah,[rcx+(number_line+1)] ; increment ah. al_not_carry: cmp bx,0 jne summing_loop ready: ; sum is now in eax. section .data max_value equ 255 max_value_plus_1 equ (max_value + 1) db max_value ; 0 - 1 = 255 number_line: %assign myValue 0 %rep max_value_plus_1 db myValue %assign myValue (myValue + 1) %endrep db 0 编辑:答案的其余部分涉及我第一次提出的更有限的解决方案

它可以通过二维查找表来完成

对于8位寄存器,例如
al
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
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
在x86和x86-64中,mov可用于256^n的乘法,即:256、65536、16777216、

将256乘以
mov
很容易计算
ax=256*bl

mov ax,0
mov ah,bl
要添加例如
al
bl
,我们需要获得正确的偏移量,它是
256*al+bl
,或者
256*bl+al
(因为查找表是对称矩阵,并且它是对称的,因为加法是一种交换操作)

在x86/x86-64中,仅使用
mov
乘以65536和更大的数字需要使用内存,因为无法直接寻址32位通用寄存器(如eax)的上16位或64位通用寄存器(如rax)的上32位

要仅使用
mov
计算
eax=65536*bx

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

...

temp dd 0
但16位值的真正问题是,在x86/x86-64中,内存是使用字节偏移量来处理的,而不是使用字/dword/qword偏移量,我们只能乘以256^n。但是,让我们先看看如果乘法和字节偏移量寻址没有问题,查找表会是什么样子。然后,查找表可以如下所示:

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
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矩阵

字号大小的单元格对于X(水平索引,或求和),都不是问题,因为x86汇编允许1、2、4和8的比例因子

编辑:更正了数组大小上的文本,它实际上略小于1 TiB

这里的问题是,仅使用
mov
不可能将Y(垂直索引,另一个和)乘以131072。因此,查找表的每一行必须重复32768次,或者更准确地说,在任何实际数据行之间必须有32767个未使用的填充行。为什么是32767因为
mov
只能用于乘以256、65536、16777216。。。因此,我们需要将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 第节.案文 全球启动 ; 必须保留al&bl ; 本规范将al和bl相加 _开始: ; 定义要求和的值(在al和bl中)。 mov al,47岁;示例一和 mov bl,55;示例二和 ; 求和代码从这里开始。 mov-ecx,0 mov-cl,al;ecx=al mov ch,bl;ecx=256*bl+al mov al,[rcx+总和查找表];从查找表中获取总和。 ; 对于32位代码,rcx->ecx ; 总数现在是艾尔。 第二节数据 y_乘以等于256 x_乘以等于256 汇总查找表: %分配myY 0 %《纽约时报》 %分配myX 0 %重复x_次 %分配myValue(myX+myY) %《纽约时报》 %如果myValue>=256 %分配myValue(myValue-256) %恩迪夫 %endrep db myValue %分配myX(myX+1) %endrep %分配