开发者

How can I do these asm ROR and BT/RCR operations in C? Rotate, or shift in a bit from another number

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...


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

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

Hope this helps


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).


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!


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)


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜