VC内联asm - 用rcl(rcr)移位

时间:2014-02-15 11:54:23

标签: visual-c++ assembly inline-assembly bit-shift

我正在使用以下函数将向量数据移位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        
};

第一个代码有什么问题,如何使用rclrcr进行转移?

1 个答案:

答案 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错误。