我使用下面的函数由1位的矢量的数据进行移位(由2多重峰):VC内联汇编 - 与RCL(RCR)移
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
进行移位?
在C中编写代码并查看编译器输出的内容 – James
CMP指令更改进位。你需要重新考虑这一点。 –
hm,我已经删除了CMP,确实有效(只能用调试器检查),但是现在我必须找到一些东西来检查计数器来结束循环。 pushf和popf? –