编辑:任何加法或减法可以做一个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
编辑:的答案涉及其他的解决方案,其余那需要更多的记忆。
编辑:一维128 KiB查找表就足以用于任何加法或减法的16位操作数。不需要巨大的查找表。 编辑:修正了导致通常设置进位标志产生不正确结果的附加错误。
下面是x86-64程序集中的代码,与YASM组装在一起,也可能与NASM组装在一起。实现add ax,bx
,仅使用mov
,cmp
& jne
。
[bits 64]
; valid commands: mov, cmp, jmp, je, jne
; used commands: 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).
mov edx,0
mov dx,ax
mov eax,edx ; eax = ax
mov ecx,0
mov cx,bx ; ecx = bx
summing_loop:
mov cx,[2*rcx+(number_line-2)] ; decrement ecx.
mov ax,[2*rax+(number_line+2)] ; increment eax.
cmp ecx,0
jne summing_loop
; sum is now in eax.
section .data
max_value equ 65535
dw max_value ; 0 - 1 = 65535
number_line:
%assign myValue 0
%rep max_value
dw myValue
%assign myValue (myValue + 1)
%endrep
dw 0
编辑:与我第一次来到了一个更为有限的解决方案的答案交易休息。
它可以用完成一个二维查找表。
对于8位寄存器,例如al
& bl
,这很容易。对于16位寄存器,它可以完成,但查找表将是巨大的(几乎1 tebibtete),请参阅下面的原因。查找表的每个单元格包含相应的X坐标的总和(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
在86和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中乘以65536和更大的数字只使用mov
需要使用内存,因为无法直接寻址32位通用寄存器(如eax)的高16位或高32位64位通用寄存器的位(如rax)。
为了计算eax = 65536 * bx
只有mov
使用:
mov [temp], dword 0
mov [temp+2], bx
mov eax, [temp]
...
temp dd 0
但随着16位值,真正的问题是,在86/x86-64的内存使用字节寻址偏置,不与字/双字/四字偏移,我们只能乘以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单元,每个单元为双字,所以每一行需要2个* 65536字节= 131072个字节。有65536行,所以它是一个65536 * 65536矩阵。
由于x86程序集允许比例因子为1,2,4和8,因此字大小的单元对于X(水平索引或任一加数)不是问题。
编辑:更正阵列大小的文本,它实际上比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 tebibyte(1的TiB)。
不幸的是,我的电脑里没有那么多的内存,但是在x86-64中是可以的。
下面是使用只mov
和256 * 256查表(与YASM测试,应与NASM组装太)为8位加法代码:
[bits 64]
; valid instructions: mov, cmp, jmp, je, jne
; used instructions: mov
section .text
global _start
; al & bl must be preserved
; this code sums al & bl
_start:
; define the values to be summed (in al & bl).
mov al,47 ; example first summand
mov bl,55 ; example second summand
; the summing code starts here.
mov ecx,0
mov cl,al ; ecx = al
mov ch,bl ; ecx = 256 * bl + al
mov al,[rcx+sum_look_up_table] ; fetch the sum from look-up table.
; for 32-bit code, rcx -> ecx
; the sum is now in al.
section .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
db myValue
%assign myX (myX + 1)
%endrep
%assign myY (myY + 1)
%endrep
如果你有递减/递增指令,你可以这样做。 – 2013-04-10 08:57:20
假设'MOV'可以从内存中移动,那么如果你在大型查找表中有大量内存需要烧录,那么这是可能的。 – harold 2013-04-10 09:04:58
@harold或者它可能是一个巨大的状态机的内存吨,其中指令指针值是状态,假设CMP可以与常量进行比较。 – 2013-04-10 09:22:10