我正在使用以下函数将向量数据移位1位(mult乘2):
vec shl(vec n) {
n.resize(n.size() + 1, 0);
unsigned int* adr = n.data();
unsigned int s = n.size();
_asm {
clc
mov ecx, 0
mov edx, dword ptr [adr]
nloop:
mov eax, dword ptr[edx + ecx * 4]
rcl eax, 1
mov dword ptr [edx + ecx * 4], eax
inc ecx
jc carryisset ; check carry - breakpoint
jmp nocarry ; ~ breakpoint
carryisset : ; ~ breakpoint
jmp nocarry ; ~ breakpoint
nocarry: ; ~ breakpoint
cmp ecx, dword ptr [s]
jl nloop
};
return n;
};
所以,我读过rcl
使用进位并将其加到高位。但是当根据调试器未设置进位位时,rcl继续将其添加到eax
例如:
#include <iostream>
#include <vector>
typedef std::vector<unsigned int> vec;
const unsigned int uint_max = (unsigned int)(~0);
vec n1 = { uint_max, 2, 2, 1, 0, 0, 0 };
vec n2
int main() {
n2 = shl(n1);
for (auto i : n2)
std::cout << i << " ";
return 0;
};
输出:
4294967294 5 5 3 1 1 1 1
使用调试器逐步执行代码:
loop: first iteration (ecx = 0)
eax <- uint_max
eax <- rotate left with carry (rcl)
now eax is uint_max - 1
jumps to carryisset (with jc), so there is a carry
loop: second iteration (ecx = 1)
eax <- 2
eax <- rotate left with carry (rcl)
now eax is 2 << 2 + (carry)1 = 5
jumps to nocarry (with jc), so there is no carry
loop: third iteration (ecx = 2)
eax <- 2
eax <- rotate left with carry (rcl)
now eax is 2 << 2 + carry (should be 0, not set), but eax gives 5 too, like there were carry.
jumps to nocarry (with jc), so there is no carry (at least according to jc)
...ect
因此,在这种情况下,第一次迭代后没有进位,但进位不会“复位”。 这个实现来自SO Large binary shifts in 8086 assembly?(接受的答案):
首先,确保进位标志为零。然后:
1.将4个字节拉入寄存器
2. RCR - 在我的情况下RCL 3.写出来 4.重复下一个4字节
然而,当我向左旋转时,进位位始终打开(或尝试使用正确,相同的结果:如果vec(2,0,0,0,0...)
为vec(1, uint_max/2 + 1, uint max/2 + 1, ...)
)
ps:我做了一个工作班次,避免了进位和检查最高位,但我认为这是一个过于复杂的:
_asm {
clc
mov edx, dword ptr [adr]
xor ebx, ebx
xor ecx, ecx
xor eax, eax
nloop:
mov eax, dword ptr[edx + ecx * 4]
push edx
mov edx, ebx
mov ebx, eax
and ebx, 0x80000000
shr ebx, 31
shl eax, 1
add eax, edx
pop edx
mov dword ptr [edx + ecx * 4], eax
inc ecx
xor eax, eax
cmp ecx, dword ptr [s]
jl nloop
};
第一个代码有什么问题,如何使用rcl
和rcr
进行转移?
答案 0 :(得分:0)
(感谢Hans。请参阅评论。)
工作代码:
clc
mov ecx, 0
mov edx, dword ptr[adr]
nloop:
pushf
cmp ecx, dword ptr [s]
je fin
popf
mov eax, dword ptr[edx + ecx * 4]
rcl eax, 1
mov dword ptr[edx + ecx * 4], eax
inc ecx
jmp nloop
fin:
popf
我先清除旗帜。在主循环中,在pushf
之后cmp
标记popf
。为此,我将比较移动到循环的开头。对于fin
只是popf
跳转后的标志,以避免ESP错误。