2014-02-15 85 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錯誤。