如何计算char [assembly]中的1/0位数

时间:2017-05-13 14:03:34

标签: assembly x86

这是汇编代码。它应该计算,在char中从1转换为0或0到1的转换次数。

void main()
{

unsigned char vet[] = { 0x06 }; //Array di byte (da considerare come
                                //una sequenza di bit)
unsigned short int len = 4;             //Lunghezza (numero di bit)

                                        // Output
unsigned int transizioni01;             //Numero di transizioni 0->1
unsigned int transizioni10;             
  __asm{XOR EAX, EAX
        XOR EBX, EBX
        MOV transizioni10, 0
        MOV transizioni01, 0
TORNO:
        CMP BX, len
        JA FINE
        MOV AL, vet[EBX]
        TEST AL, 1
        JNZ UNO

        INC BX
        MOV AL, vet[EBX]
        TEST AL, 1
        JZ ZEROUNO

UNO:    INC BX
        CMP BX, len
        JA FINE
        MOV AL, vet[EBX]
        TEST AL, 1
        JNZ TORNO

UNOZERO:INC transizioni10
        JMP TORNO
ZEROUNO:INC transizioni01
        JMP TORNO

FINE:}

它无法正常工作。任何人都建议我改变吗?

2 个答案:

答案 0 :(得分:0)

我没有尝试理解您的代码,但以下替代方案可行:

//Assume EAX = pointer to input array of integer
//Assume EDX = length of array in bytes
//Length must be a multiple of 4.
  push edi               //Save non-volatile registers
  push ebx               //I.e. everything but eax,ecx,edx
  xor edi,edi            //change count = 0
  lea eax,[eax+edx]      //array = end of array
  neg edx                //length = - length
  //we turn the counter around, so the loop is more efficient.
  jz @Done               //if length = 0 -> done
@OuterLoop:
  mov ebx,[eax+edx]      //x = array[end - length] => x = array[begin]
@InnerLoop
  bsf ecx,ebx       //count leading zero's, cl = LSB zero-count
  jz @RemainderIsZero
  inc edi           //If reg is non-zero then at least 1 change.
  shr ebx,cl        //shift out the bits we've counted
  not ebx           //Invert the data, force LSB to be zero
  jmp @InnerLoop    //repeat until data = 0 (until no more changes)
@RemainderIsZero:    
  add edx,4         //see if more data needs to be processed
  jnz @OuterLoop    //remember edx is negative
@Done:
  mov eax,edi       //return the count in eax
  pop ebx           //restore the non-volatile registers.
  pop edi
  //ret             //You can only do RET if the compiler does NOT
                    //use stack frames.  

答案 1 :(得分:0)

假设数组从低位到高位连接,即两个字节0x0F, 0xF0将被视为位流0000 1111 1111 0000,从而导致一个(0-> 1)更改,和(1-> 0)改变。第一个/最后一个位总是"没有变化" (对着它旁边的空隙),所以0xFF, 0xFF将产生0/0转换,0x00, 0x00也将产生0/0转换。

代码的想法是使用(X xor (X>>1))提取位的位掩码,其中发生转换(" edge"),然后计算这些以计算" all&# 34;转换,当and - 用原始X值时,只有" 0-> 1"的位掩码。收到过渡,并再次计算。然后在结束时计算" 1-> 0"转换只需要减去" 0-> 1"来自"所有"计数。

    ; TODO preserve registers which need to be preserved by your ABI
    ; ax, ebx, ecx, dx, esi, edi will be modified
    lea    esi,[vet]  ; address of byte array
    mov    ecx,[len]  ; number of bytes in array
    mov    ah,[esi]   ; take most significant bit as entry low bit
    shr    ah,7       ; ah.LSB = [first_byte].MSB (no transition on first bit)
    xor    ebx,ebx    ; counter of ALL transitions
    xor    edi,edi    ; counter of 0->1 transitions
    ; ## calculate bitmaks of all transitions (marked bit is the second one)
detect_transitions_loop:
    mov    al,[esi]   ; ax = current source byte + low bit of previous in ah
    shr    ax,1       ; al = 8 bits of array shifted by 1 to right
    mov    ah,[esi]   ; ah = current source byte
    inc    esi        ; ++source byte address
    xor    al,ah      ; al = bitmask of transitions detected
    jz     no_transition_detected_in_byte
    mov    dh,al      ; dh = copy of all transitions
    ; ## count all transitions
count_all_transitions:
    inc    ebx        ; increment number of all transitions
    ; clear least significant set bit of al (removes one transition)
    mov    dl,al
    dec    al
    and    al,dl
    jnz    count_all_transitions ; until all bits are counted
    ; ## count 0-1 transitions
    and    dh,ah      ; dh = bits of 0->1 transitions detected
    jz     no_transition_detected_in_byte
count_01_transitions:
    inc    edi        ; increment number of 0->1 transitions
    ; clear least significant set bit of dh (removes one transition)
    mov    dl,dh
    dec    dh
    and    dh,dl
    jnz    count_01_transitions ; until all bits are counted
no_transition_detected_in_byte:
    dec    ecx
    jnz    detect_transitions_loop
    ; ## calculate 1->0 transitions count, and store results
    sub    ebx,edi
    mov    [transizioni01],edi
    mov    [transizioni10],ebx
    ; TODO restore any registers which had to be preserved
    ; TODO return

代码可以扩展为一次处理32位(如果填充输入数组包含4个输入字节的乘法),并且(在可用的CPU上)指令popcnt可用于计算数量检测到的转换位。

编辑:实际上要一次处理32位的数组,需要将这些位以top->低和反向连接(从LSB到MSB读取它们,即0x0F = 1111 0000位流),然后在小端机器上加载mov eax,[esi]将符合这一点。所以它并不像我想的那么简单。