2014-02-15 56 views
0

我使用下面的函数由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   
}; 

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

+0

在C中编写代码并查看编译器输出的内容 – James

+1

CMP指令更改进位。你需要重新考虑这一点。 –

+0

hm,我已经删除了CMP,确实有效(只能用调试器检查),但是现在我必须找到一些东西来检查计数器来结束循环。 pushf和popf? –

回答

0

(感谢汉斯看到评论。)

工作代码:

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