2014-02-15 3 views
0

(2에 의한 멀티 포트) : 그래서VC의 인라인 어셈블리 - RCL (RCR)로 이동 내가 1 비트에 의해 벡터의 데이터를 이동하기 위해 다음과 같은 기능을 사용하고

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? (허용 대답)에서 온 :

첫째, 캐리 플래그가 제로 있는지 확인합니다. 캐리 비트는 항상 내 경우 RCL 다시 밖으로
를 반복 다음 4 바이트

3. 쓰기에서 그러나 -
1. 풀 레지스터
2 RCR로 4 바이트 : 그럼 I 좌측 회전시에 (또는 오른쪽으로 동일한 결과를 시도 : vec(2,0,0,0,0...) 경우에서이다 vec(1, uint_max/2 + 1, uint max/2 + 1, ...))

PS : I가 작동 시프트 반송을 방지하고, 최상위 비트를 체크했다하지만 내 생각 overcomplicated이다 :

_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를 삭제했습니다. 푸시와 팝프? –

답변

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 

내가 먼저 깃발을 취소합니다. 메인 루프에서 pushfcmp에 대한 플래그이며, popf 이후입니다. 이를 위해 비교를 루프의 시작 부분으로 옮겼습니다. fin의 경우 popf은 ESP 오류를 피하기 위해 점프 후 플래그입니다.