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