XMM register instructions and their c equivalents
Clash Royale CLAN TAG#URR8PPP
up vote
2
down vote
favorite
I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.
movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result
I've tried various forms of casting float
and double
to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd
and cvtpd2ps
instructions.
What would the above code look like in c/c++ and what is the resulting data type?
x86 float
add a comment |Â
up vote
2
down vote
favorite
I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.
movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result
I've tried various forms of casting float
and double
to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd
and cvtpd2ps
instructions.
What would the above code look like in c/c++ and what is the resulting data type?
x86 float
1
I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.
movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result
I've tried various forms of casting float
and double
to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd
and cvtpd2ps
instructions.
What would the above code look like in c/c++ and what is the resulting data type?
x86 float
I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.
movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result
I've tried various forms of casting float
and double
to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd
and cvtpd2ps
instructions.
What would the above code look like in c/c++ and what is the resulting data type?
x86 float
asked Sep 6 at 22:18
Twifty
2078
2078
1
I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41
add a comment |Â
1
I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41
1
1
I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41
I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
8
down vote
accepted
You likely won't get an exact reproduction because cvtdq2pd
takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax
here, there are probably better(?) instructions to use.
cvtsi2sd xmm0, eax
will do the same thing as
movd xmm0,eax
cvtdq2pd xmm0,xmm0
See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html
So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.
Onto your actual question:
cvtpd2ps xmm0,xmm0 ; double to packed?
CVTPD2PS xmm1, xmm2/m128
Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.
This will pack the two double precision floats at xmm0[0:63]
& xmm0[64:127]
into the lower 64 bits of xmm0
, converting them from double to single precision floating point values (xmm0[0:31]
& xmm0[32:63]
).
Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html
So if the lower 64 bits of xmm0
represented a double
, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0
.
movss dword ptr ds:[ebx+0x34],xmm0
MOVSS xmm2/m32, xmm1
Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.
Now stores the 4 byte result from xmm0[0:31]
into [ebx+0x34]
, which we know is a single precision float
from the result of the cvtpd2ps
operation.
So the result of this operation is a 32 bit float
.
Ref: https://www.felixcloutier.com/x86/MOVSS.html
This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.
double* d_arr = (double*)0x4F6CC0;
int main()
int in = 4;
int signbit = ((unsigned int)in >> 31);
float result = *(double*)(d_arr + signbit) + in;
return 0;
Conclusion:
cvtdq2pd
& cvtpd2ps
are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0
are never relevant to the result.
Disclaimer:
I've never used floating point assembly before. I just looked up the docs now. I could be missing something.
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
8
down vote
accepted
You likely won't get an exact reproduction because cvtdq2pd
takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax
here, there are probably better(?) instructions to use.
cvtsi2sd xmm0, eax
will do the same thing as
movd xmm0,eax
cvtdq2pd xmm0,xmm0
See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html
So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.
Onto your actual question:
cvtpd2ps xmm0,xmm0 ; double to packed?
CVTPD2PS xmm1, xmm2/m128
Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.
This will pack the two double precision floats at xmm0[0:63]
& xmm0[64:127]
into the lower 64 bits of xmm0
, converting them from double to single precision floating point values (xmm0[0:31]
& xmm0[32:63]
).
Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html
So if the lower 64 bits of xmm0
represented a double
, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0
.
movss dword ptr ds:[ebx+0x34],xmm0
MOVSS xmm2/m32, xmm1
Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.
Now stores the 4 byte result from xmm0[0:31]
into [ebx+0x34]
, which we know is a single precision float
from the result of the cvtpd2ps
operation.
So the result of this operation is a 32 bit float
.
Ref: https://www.felixcloutier.com/x86/MOVSS.html
This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.
double* d_arr = (double*)0x4F6CC0;
int main()
int in = 4;
int signbit = ((unsigned int)in >> 31);
float result = *(double*)(d_arr + signbit) + in;
return 0;
Conclusion:
cvtdq2pd
& cvtpd2ps
are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0
are never relevant to the result.
Disclaimer:
I've never used floating point assembly before. I just looked up the docs now. I could be missing something.
add a comment |Â
up vote
8
down vote
accepted
You likely won't get an exact reproduction because cvtdq2pd
takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax
here, there are probably better(?) instructions to use.
cvtsi2sd xmm0, eax
will do the same thing as
movd xmm0,eax
cvtdq2pd xmm0,xmm0
See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html
So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.
Onto your actual question:
cvtpd2ps xmm0,xmm0 ; double to packed?
CVTPD2PS xmm1, xmm2/m128
Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.
This will pack the two double precision floats at xmm0[0:63]
& xmm0[64:127]
into the lower 64 bits of xmm0
, converting them from double to single precision floating point values (xmm0[0:31]
& xmm0[32:63]
).
Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html
So if the lower 64 bits of xmm0
represented a double
, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0
.
movss dword ptr ds:[ebx+0x34],xmm0
MOVSS xmm2/m32, xmm1
Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.
Now stores the 4 byte result from xmm0[0:31]
into [ebx+0x34]
, which we know is a single precision float
from the result of the cvtpd2ps
operation.
So the result of this operation is a 32 bit float
.
Ref: https://www.felixcloutier.com/x86/MOVSS.html
This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.
double* d_arr = (double*)0x4F6CC0;
int main()
int in = 4;
int signbit = ((unsigned int)in >> 31);
float result = *(double*)(d_arr + signbit) + in;
return 0;
Conclusion:
cvtdq2pd
& cvtpd2ps
are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0
are never relevant to the result.
Disclaimer:
I've never used floating point assembly before. I just looked up the docs now. I could be missing something.
add a comment |Â
up vote
8
down vote
accepted
up vote
8
down vote
accepted
You likely won't get an exact reproduction because cvtdq2pd
takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax
here, there are probably better(?) instructions to use.
cvtsi2sd xmm0, eax
will do the same thing as
movd xmm0,eax
cvtdq2pd xmm0,xmm0
See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html
So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.
Onto your actual question:
cvtpd2ps xmm0,xmm0 ; double to packed?
CVTPD2PS xmm1, xmm2/m128
Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.
This will pack the two double precision floats at xmm0[0:63]
& xmm0[64:127]
into the lower 64 bits of xmm0
, converting them from double to single precision floating point values (xmm0[0:31]
& xmm0[32:63]
).
Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html
So if the lower 64 bits of xmm0
represented a double
, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0
.
movss dword ptr ds:[ebx+0x34],xmm0
MOVSS xmm2/m32, xmm1
Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.
Now stores the 4 byte result from xmm0[0:31]
into [ebx+0x34]
, which we know is a single precision float
from the result of the cvtpd2ps
operation.
So the result of this operation is a 32 bit float
.
Ref: https://www.felixcloutier.com/x86/MOVSS.html
This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.
double* d_arr = (double*)0x4F6CC0;
int main()
int in = 4;
int signbit = ((unsigned int)in >> 31);
float result = *(double*)(d_arr + signbit) + in;
return 0;
Conclusion:
cvtdq2pd
& cvtpd2ps
are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0
are never relevant to the result.
Disclaimer:
I've never used floating point assembly before. I just looked up the docs now. I could be missing something.
You likely won't get an exact reproduction because cvtdq2pd
takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax
here, there are probably better(?) instructions to use.
cvtsi2sd xmm0, eax
will do the same thing as
movd xmm0,eax
cvtdq2pd xmm0,xmm0
See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html
So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.
Onto your actual question:
cvtpd2ps xmm0,xmm0 ; double to packed?
CVTPD2PS xmm1, xmm2/m128
Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.
This will pack the two double precision floats at xmm0[0:63]
& xmm0[64:127]
into the lower 64 bits of xmm0
, converting them from double to single precision floating point values (xmm0[0:31]
& xmm0[32:63]
).
Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html
So if the lower 64 bits of xmm0
represented a double
, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0
.
movss dword ptr ds:[ebx+0x34],xmm0
MOVSS xmm2/m32, xmm1
Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.
Now stores the 4 byte result from xmm0[0:31]
into [ebx+0x34]
, which we know is a single precision float
from the result of the cvtpd2ps
operation.
So the result of this operation is a 32 bit float
.
Ref: https://www.felixcloutier.com/x86/MOVSS.html
This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.
double* d_arr = (double*)0x4F6CC0;
int main()
int in = 4;
int signbit = ((unsigned int)in >> 31);
float result = *(double*)(d_arr + signbit) + in;
return 0;
Conclusion:
cvtdq2pd
& cvtpd2ps
are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0
are never relevant to the result.
Disclaimer:
I've never used floating point assembly before. I just looked up the docs now. I could be missing something.
edited Sep 7 at 8:29
0xC0000022L♦
7,48742860
7,48742860
answered Sep 7 at 1:41


Abigail
3216
3216
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19275%2fxmm-register-instructions-and-their-c-equivalents%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41