what does this code on IDA? i've found with this a couple of times and i don't have idea what means.
int a5;
int dGainMax;
COERCE_DOUBLE(__PAIR__(a5, dGainMax))
Reverse Engineering Stack Exchange is a question and answer site for researchers and developers who explore the principles of a system through analysis of its structure, function, and operation. It only takes a minute to sign up.
Sign up to join this communitywhat does this code on IDA? i've found with this a couple of times and i don't have idea what means.
int a5;
int dGainMax;
COERCE_DOUBLE(__PAIR__(a5, dGainMax))
__PAIR__()
seems to be a macro that computes an unsigned long
value from its two arguments, which it interprets as containing the high and low bits of that value.
The topic linked by Guntram - Understanding __PAIR__ macro from IDA PRO Pseudo Decompiler to look better contains a definition for the macro and examples of its use, but no explanation of it.
// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((unsigned long)(high)<<sizeof(high)*8) | low)
The macro doesn't make a lot of sense. Either it was transcribed erroneously (with the original containing sizeof(low)
instead of sizeof(high)
) or the above-mentioned pseudo decompiler uses it only in cases where it works.
If the following conditions hold:
CHAR_BIT == 8
sizeof(high) < sizeof(unsigned long)
sizeof(low) <= sizeof(high)
then the macro can be used to form a value of double register width - like DX:AX - from two register-width values.
Condition 2 is necessary because otherwise the behaviour would be undefined (no-op on Intel chips, for example, since they mask shifts for registers <= 32 bit with 31). Condition 3 is necessary because otherwise 'excess' bits in low
could bleed over the bits of high
in the resulting value.
The comment and the context (usage example) suggest that
sizeof(unsigned long) == sizeof(uint64_t)
sizeof(int) == sizeof(int32_t)
This implies a compiler of the LP64 variety, like those usually found in 64-bit UNIX (not the LLP64 kind common on Wintel platforms).
The naming of the COERCE_DOUBLE
macro is a bit unfortunate since it probably refers to converting the value to a double while 'coercing' might also mean reinterpreting the bits as a floating point value, something which certain programming tricks used to rely on.
Also, there is some ambiguity regarding the conversion. The x86 FPU can load signed integers directly into floating point registers (FILD) but not unsigned ones, which means that x86 compilers have to emit a load of extra code for converting unsigned integers.
This means that the __PAIR__
macro with its implied unsignedness can erroneously suggest major inefficiencies that aren't there, since x86 CPUs tend to interpret double-width register values are as signed whenever signedness matters (see instructions like CDQ, DIV or FILD, for example). The devil is in the details which are hidden and glossed over by the strange macros. Hence it is advisable to consult the disassembly to find out what's really going on, even though the SP simulation of the disassembler can be a bit off on occasion.