編輯:任何加法或減法可以做一個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