tags:

views:

219

answers:

5

Hello, I'm converting some assembly code to C to be able to use it with the current compiler environment I have to work with.

I've reached 2 operations I don't know how to translate to C. Anyone know how to do it?

In both, offset is an unsigned 32-bit integer and shift is a signed integer value. C_FLAG is a bool.

OP1:

__asm {
    __asm mov ecx, shift
    __asm ror offset, cl
}

OP2:

__asm {
    __asm bt dword ptr C_FLAG, 0
    __asm rcr offset, 1
}

Thank you very much for your expertise.

P.S.: I'm not the original developer, nor I have seen many x86 assembly code...

+2  A: 

rotate right discussion: http://www.osix.net/modules/article/?id=320

pictorial descriptions: http://www.penguin.cz/~literakl/intel/r.html

Hope this helps

aaa
Thank you, the rotate right discussion served very well for the first operation.
Juan Antonio
A: 

For bit shifting, as per your first example, use the << operator. In the C language there is no wrap-around for shifts, often termed as rotates. You would have to implement the operation yourself:

unsigned char carry;
carry = byte & 0x80; // Save the Most Significant bit for 8-bit byte.
byte <<= 1;  // Left shift by one, insert a 0 as the least significant bit.
byte |= carry;  // Put the rotated bit back into the byte.

Some processors also have a rotate through carry operation which will rotate the carry value in the next shift. This assumes that the carry be a global variable.

To test bits in the C language, you will use the & (binary AND operator) and maybe the ~ operator (negate). To test the most significant bit in an 8-bit byte:

   if (byte & 0x80)
   {
      // bit is a 1
   }
   else
   {
      // bit is a 0
   }

With all that said, you will have to find out why the carry flag (C_FLAG) is used and design a different system around it. Generally, the carry bit is invalid outside of the assembly language function that it is used in. Some tightly coupled assembly language functions may violate this rule. In that case, rewrite the assembly language rather than debugging it. Redesign the whole program!

Thomas Matthews
That is left rotations and your carry bit ends up in the wrong place anyway.
nategoose
A: 

for the second op

__asm bt dword ptr C_FLAG, 0

sets the carry bit flag to C_FLAG (so 1 or 0)

__asm rcr offset, 1

is Rotate Carry Left which is a 33 bit rotate using the carry flag as the 33rd bit. (and the results put the 33rd bit in the carry flag. Which (I think) is the same as

offset =  offset << 1 + C_FLAG ? 1:0

(unless you care about the carry flag later)

EDIT - for some reason I was reading rcr as rcl. So more like

offset = offset >> 1 | (C_FLAG ? 1<<31 : 0)
aspo
`1UL<<31` is better (`1<<31` gives undefined behaviour on systems where `int` can't represent that number, whereas that is within the guaranteed range of `unsigned long`).
caf
A: 

Although it's more or less covered, I'd do it this way:

OP 1: It's a rotate right operation over offset, shift places. In C it could be something like this:

offset = (offset >> shift) | (offset << (WORD_LENGTH - shift);

You could get the word length with sizeof(void *) * 8 for example.


OP 2: I think this op is implementing the RRX operation in x86 assembly. It's another type of rotate right operation where the carry flag is used to provide a 33 bit quantity to be shifted. In C it could be something like this:

offset = (C_FLAG << 31) | (offset >> 1);

Where C_FLAG is the carry flag, you should find more about what that bool value is really being used for in the code you have.

Xandy
A: 

Assuming that the flags are not used to hold persistent state (which is a reasonable assumption), OP1 is equivalent to:

/* Precondition: `*offset` is in range 0..0xFFFFFFFF */
void inline op1(unsigned long *offset, int shift)
{
    shift = ((unsigned)shift) % 32;

    if (shift)
        *offset = ((*offset >> shift) | (*offset << (32 - shift))) & 0xFFFFFFFFUL;
}

and OP2 is equivalent to:

/* Precondition: `*offset` is in range 0..0xFFFFFFFF */
void inline op2(unsigned long *offset, unsigned long C_FLAG)
{
    *offset = (*offset >> 1) | ((C_FLAG & 1) << 31);
}

(On systems with 32 bit long, the precondition is automatically satisfied).

caf
Thank you very much, after some reading I think this one is the right answer. What I don't really know is why the bt operation in the 2nd op, if it is a rotate through carry right wont rcr be enough?
Juan Antonio
@Juan Antonio: `BT` is what actually *sets* the carry flag - in this case, it sets the carry flag to bit 0 of `C_FLAG`, which is a 32 bit memory operand.
caf
Thank you for the explanation, the carry flag might had the result from a previous operation.
Juan Antonio