我被下面的代码卡住了。我有以下代码的Tracer和SCO调试器。我编译它使用Dosbox,我想添加左旋转的代码,但我不能找到在哪里,我试图广告ROL AX,1,但它是行不通的。
让我们说数字是
偶数
奇数 1,3,5,7,9
3、6、10、14、20之和
我想让它看起来像
3,5,7,11,2
所以总和就是
4,8,12,18,11
_EXIT = 1
.SECT .TEXT
start:
MOV BX, 0
MOV CX, 5
sum:
CMP BX, 5
JE done
NOP
MOVB AL,(BX)
ADD BX,odd
MOVB DL,(BX)
SUB BX,odd
ADDB AL,DL
ADD BX,result
MOV (BX),AX
SUB BX,result
INC BX
LOOP sum
done:
MOV CX,5
MOV BX,result
print:
CMP BX,result + 5
JE exit
MOVB AL,(BX)
INC BX
LOOP print
exit:
PUSH _EXIT
SYS
.SECT .DATA
prime:
.BYTE 2,3,5,7,11
odd:
.BYTE 1,3,5,7,9
result:
.BYTE 0,0,0,0,0
.SECT .BSS
rol ax, 1
工作在该寄存器中的位,而不是数组中的字节。 你要找的是像C++ std::rotate(first, new_first, last)
来旋转数组元素。
你可以在内存中用 rol word [mem], 8
或者甚至做一个8、16或24位的二进制字旋转,以重新排列4个字节中的字节,但这是你能做的所有旋转。
因此,例如你可以这样做。
;; starting with prime = .byte 2,3,5,7,11
ror dword ptr [prime], 8 ; 3,5,7,2, 11 ; x86 is little-endian
ror word ptr [prime+4], 8 ; 3,5,7, 11,2
那是GAS .intel_syntax
我不认识你使用的语法。 它看起来像是AT&T和Intel的混合体,寻址模式是圆括号,但它看起来确实是目的地在左边。
与仅仅加载所有5个字节并将它们存储回你想要的地方相比,这是相当低效的。 具体来说,当第2个字加载部分的时候,你会得到一个存储转发的停顿。ror
读取刚才由第一段的dword存储部分存储的1个字节。ror
. (一条内存定位指令解码为加载+ALU+存储操作。 当第2次旋转的加载执行时,第一个存储仍将在存储缓冲区中。 假设一个现代的x86 CPU原生执行这段代码;但由于你在DOSBox中,它实际上是被模拟而不是执行)。)
更直接的方法是。
mov eax, [prime+1] ; dword load: 3,5,7,11
mov dl, [prime] ; byte load: 2
mov [prime], eax
mov [prime+4], cl ; 3,5,7,11,2
这很容易扩展到更大的数组大小. 如果需要的话,你可以写一个循环来向前面复制元素,同时把原来的第一个元素保存在其他地方(寄存器中)。