Ryan
Ryan

Reputation: 443

add up all 1 bits in x86 assembly

I don't really have a clue of what I'm doing... The goal is to add up all the 1's and if its even say so and if its odd say so a C/C++ section gives the variables that are passed into asm

#include <stdint.h>
#include <stdio.h>
#include <iostream>
using namespace std;

extern "C" {
    bool    isBitCountEven(int32_t);
}

static int32_t testData[] = {
    0x0,
    0x1,
    0x2,
    0x4,
    0x8,
    0x40000000,
    0x80000000,
    0x00000002,
    0xe,
    0xff770001,
    0xffeeeeff,
    0xdeadbeef,
    0xbaddf00d,
    0xd00fefac,
    0xfaceecaf,
    0xffffffff,
    0xaaaa5555
};
#define NUM_TEST_CASES  (sizeof (testData) / sizeof (*testData))


int main()
{
    printf(" ICE#10 \n\n");

    for (int i = 0; i < NUM_TEST_CASES; i++) {
        printf("isBitCountEven(0x%8x) yields: %s\n", testData[i], isBitCountEven(testData[i]) ? "true" : "false");
    }
    system("PAUSE");
    return 0;
}

And this is my asm. It doesn't output anything. Prologue and epilogue are just things Ive copped and pasted from other work that worked well so disregard those, I know they may be garbage

Here is my asm

        .386P           ; use 80386 instruction set
        .MODEL flat,C     ; use flat memory model

        printf PROTO C, :VARARG

        .DATA           ; declare initialzed data here

        .STACK          ; use default 1k stack space

        .CODE           ; contains our code


    ;-------------------PART 1------------------------------------------------------------
    ;if (the number of 1 bits in the binary representation of val is even)
    ;               return true;
    ;           else        
    ;               return false;
    ;       }
    ;
    ;--------------------------------------------------------------------------------------
    isBitCountEven PROC PUBLIC
        PUSH    ebp             ; save caller base pointer
        MOV     ebp, esp        ; set our base pointer
        SUB     esp, (1 * 4)    ; allocate uint32_t local vars
        PUSH    edi
        PUSH    esi
        ; end prologue

        MOV     al, [ebp + 8]
    ;now walk down the variable and count the number of 1

    SHIFT:
        SHL al, 1
        JNC SKIP
        INC ebx
    SKIP:
        loop SHIFT

    FINALE:             ;see if it adds up to ebx
    TEST al, al
    JP FALSE
    TEST ebx, 1 
    JZ TRUE



TRUE:
    MOV     eax,1
    POP     esi                 ; start epilogue
    POP     edi
    MOV     esp, ebp            ; deallocate locals
    POP     ebp                 ; restore caller base pointer
    RET
FALSE:
    MOV     eax, 0
    POP     esi                 ; start epilogue
    POP     edi
    MOV     esp, ebp            ; deallocate locals
    POP     ebp                 ; restore caller base pointer
    RET
isBitCountEven ENDP ; end the procedure
END isBitCountEven

What should I do I am completely lost and am horrible at asm...

Upvotes: 0

Views: 826

Answers (1)

user555045
user555045

Reputation: 64904

It can be simplified quite a bit, mostly by getting rid of all the stack frame business (it's really not necessary, there is no dynamic stack allocation) and by using setcc instead of branching.

You can count the bits of an int32_t with popcnt, then test whether the count is even,

isBitCountEven PROC PUBLIC
    mov eax, dword ptr [esp + 4]
    popcnt eax, eax
    test al, 1
    setz al    ; if the lowest bit of the count is zero, its even
    ret
isBitCountEven ENDP

An other simple way it to use the parity flag, but it only checks the parity of the low byte so it takes a bit of reduction first,

isBitCountEven PROC PUBLIC
    mov eax, dword ptr [esp + 4]
    mov edx, eax
    shr eax, 16
    xor eax, edx
    xor al, ah ; all 4 bytes are now XORed together, parity flag reflects total parity
    setpe al   ; set al to 1 if parity is even, 0 if odd
    ret
isBitCountEven ENDP

Upvotes: 2

Related Questions