I'm trying to manually translate some assembly into C/C in order to migrate a code-base to x64 bit as Visual Studio does not allow __asm
code to compile in x64 bit.
I've translated some parts, however I am stuck on the following (it's an extract from the full function but should be self-contained):
void Foo()
{
char cTemp = ...;
int iVal = ...;
__asm
{
mov ebx, iVal
mov dl, cTemp
mov al, dl
MOV CL, 3
CLC
MOV AX, BX
ROR AH, CL
XOR DL, AH
SAR DL, 1
RCL BX, 1
RCL DL, 1
}
}
The parts I'm struggling with are:
RCL BX, 1
RCL DL, 1
From what I understand this is the equivalent of the following:
short v = ...;
v = (v << 1) (CLEAR_FLAG ? 1 : 0)
Which from my understanding means if the value of (v << 1)
overflows then add 1, otherwise add 0 (I may be mis-understanding though, so please correct me if so).
What I'm struggling to do is detect the overflow in C/C when carrying the shift operation. I've looked around and the only thing I can find is detecting addition/subtraction overflow before it happens, but nothing with regards to bit shifting.
Is it possible at all to translate such assembly to C/C ?
CodePudding user response:
RCL
is a "rotate left with carry" operation. So you need to take into account the previous instruction, SAR
, that sets the carry flag (CF).
Note that SAR
is a signed right shift, so will need a signed operand. It important to use proper data types that match the instruction precisely in bitness and signedness.
A 1-to-1 translation could look something like this
int8_t dl = /* ... */;
uint16_t bx = /* ... */;
// SAR DL,1
int8_t carry_1 = dl & 1;
dl >>= 1;
// RCL BX,1
uint16_t carry_2 = bx >> 15;
bx = (bx << 1) | carry_1;
// RCL DL,1
dl = (dl << 1) | carry_2;
There is probably a way to simplify these further. There are tools that can do that, they provide a somewhat readable C equivalent for a decompiled function.